1. Project Clover database Fri Apr 26 2024 18:06:03 CDT
  2. Package org.apache.commons.lang3

File StringUtils.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

1,140
1,666
227
1
9,174
2,726
948
0.57
7.34
227
4.18

Classes

Class Line # Actions
StringUtils 117 1,666 0% 948 28
0.990768299.1%
 

Contributing tests

This file is covered by 526 tests. .

Source view

1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10    *
11    * Unless required by applicable law or agreed to in writing, software
12    * distributed under the License is distributed on an "AS IS" BASIS,
13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    * See the License for the specific language governing permissions and
15    * limitations under the License.
16    */
17    package org.apache.commons.lang3;
18   
19    import java.io.UnsupportedEncodingException;
20    import java.nio.charset.Charset;
21    import java.text.Normalizer;
22    import java.util.ArrayList;
23    import java.util.Arrays;
24    import java.util.Iterator;
25    import java.util.List;
26    import java.util.Locale;
27    import java.util.Objects;
28    import java.util.regex.Pattern;
29   
30    /**
31    * <p>Operations on {@link java.lang.String} that are
32    * {@code null} safe.</p>
33    *
34    * <ul>
35    * <li><b>IsEmpty/IsBlank</b>
36    * - checks if a String contains text</li>
37    * <li><b>Trim/Strip</b>
38    * - removes leading and trailing whitespace</li>
39    * <li><b>Equals/Compare</b>
40    * - compares two strings null-safe</li>
41    * <li><b>startsWith</b>
42    * - check if a String starts with a prefix null-safe</li>
43    * <li><b>endsWith</b>
44    * - check if a String ends with a suffix null-safe</li>
45    * <li><b>IndexOf/LastIndexOf/Contains</b>
46    * - null-safe index-of checks
47    * <li><b>IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut</b>
48    * - index-of any of a set of Strings</li>
49    * <li><b>ContainsOnly/ContainsNone/ContainsAny</b>
50    * - does String contains only/none/any of these characters</li>
51    * <li><b>Substring/Left/Right/Mid</b>
52    * - null-safe substring extractions</li>
53    * <li><b>SubstringBefore/SubstringAfter/SubstringBetween</b>
54    * - substring extraction relative to other strings</li>
55    * <li><b>Split/Join</b>
56    * - splits a String into an array of substrings and vice versa</li>
57    * <li><b>Remove/Delete</b>
58    * - removes part of a String</li>
59    * <li><b>Replace/Overlay</b>
60    * - Searches a String and replaces one String with another</li>
61    * <li><b>Chomp/Chop</b>
62    * - removes the last part of a String</li>
63    * <li><b>AppendIfMissing</b>
64    * - appends a suffix to the end of the String if not present</li>
65    * <li><b>PrependIfMissing</b>
66    * - prepends a prefix to the start of the String if not present</li>
67    * <li><b>LeftPad/RightPad/Center/Repeat</b>
68    * - pads a String</li>
69    * <li><b>UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize</b>
70    * - changes the case of a String</li>
71    * <li><b>CountMatches</b>
72    * - counts the number of occurrences of one String in another</li>
73    * <li><b>IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable</b>
74    * - checks the characters in a String</li>
75    * <li><b>DefaultString</b>
76    * - protects against a null input String</li>
77    * <li><b>Rotate</b>
78    * - rotate (circular shift) a String</li>
79    * <li><b>Reverse/ReverseDelimited</b>
80    * - reverses a String</li>
81    * <li><b>Abbreviate</b>
82    * - abbreviates a string using ellipsis or another given String</li>
83    * <li><b>Difference</b>
84    * - compares Strings and reports on their differences</li>
85    * <li><b>LevenshteinDistance</b>
86    * - the number of changes needed to change one String into another</li>
87    * </ul>
88    *
89    * <p>The {@code StringUtils} class defines certain words related to
90    * String handling.</p>
91    *
92    * <ul>
93    * <li>null - {@code null}</li>
94    * <li>empty - a zero-length string ({@code ""})</li>
95    * <li>space - the space character ({@code ' '}, char 32)</li>
96    * <li>whitespace - the characters defined by {@link Character#isWhitespace(char)}</li>
97    * <li>trim - the characters &lt;= 32 as in {@link String#trim()}</li>
98    * </ul>
99    *
100    * <p>{@code StringUtils} handles {@code null} input Strings quietly.
101    * That is to say that a {@code null} input will return {@code null}.
102    * Where a {@code boolean} or {@code int} is being returned
103    * details vary by method.</p>
104    *
105    * <p>A side effect of the {@code null} handling is that a
106    * {@code NullPointerException} should be considered a bug in
107    * {@code StringUtils}.</p>
108    *
109    * <p>Methods in this class give sample code to explain their operation.
110    * The symbol {@code *} is used to indicate any input including {@code null}.</p>
111    *
112    * <p>#ThreadSafe#</p>
113    * @see java.lang.String
114    * @since 1.0
115    */
116    //@Immutable
 
117    public class StringUtils {
118    // Performance testing notes (JDK 1.4, Jul03, scolebourne)
119    // Whitespace:
120    // Character.isWhitespace() is faster than WHITESPACE.indexOf()
121    // where WHITESPACE is a string of all whitespace characters
122    //
123    // Character access:
124    // String.charAt(n) versus toCharArray(), then array[n]
125    // String.charAt(n) is about 15% worse for a 10K string
126    // They are about equal for a length 50 string
127    // String.charAt(n) is about 4 times better for a length 3 string
128    // String.charAt(n) is best bet overall
129    //
130    // Append:
131    // String.concat about twice as fast as StringBuffer.append
132    // (not sure who tested this)
133   
134    /**
135    * A String for a space character.
136    *
137    * @since 3.2
138    */
139    public static final String SPACE = " ";
140   
141    /**
142    * The empty String {@code ""}.
143    * @since 2.0
144    */
145    public static final String EMPTY = "";
146   
147    /**
148    * A String for linefeed LF ("\n").
149    *
150    * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
151    * for Character and String Literals</a>
152    * @since 3.2
153    */
154    public static final String LF = "\n";
155   
156    /**
157    * A String for carriage return CR ("\r").
158    *
159    * @see <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.6">JLF: Escape Sequences
160    * for Character and String Literals</a>
161    * @since 3.2
162    */
163    public static final String CR = "\r";
164   
165    /**
166    * Represents a failed index search.
167    * @since 2.1
168    */
169    public static final int INDEX_NOT_FOUND = -1;
170   
171    /**
172    * <p>The maximum size to which the padding constant(s) can expand.</p>
173    */
174    private static final int PAD_LIMIT = 8192;
175   
176    /**
177    * <p>{@code StringUtils} instances should NOT be constructed in
178    * standard programming. Instead, the class should be used as
179    * {@code StringUtils.trim(" foo ");}.</p>
180    *
181    * <p>This constructor is public to permit tools that require a JavaBean
182    * instance to operate.</p>
183    */
 
184  1 toggle public StringUtils() {
185  1 super();
186    }
187   
188    // Empty checks
189    //-----------------------------------------------------------------------
190    /**
191    * <p>Checks if a CharSequence is empty ("") or null.</p>
192    *
193    * <pre>
194    * StringUtils.isEmpty(null) = true
195    * StringUtils.isEmpty("") = true
196    * StringUtils.isEmpty(" ") = false
197    * StringUtils.isEmpty("bob") = false
198    * StringUtils.isEmpty(" bob ") = false
199    * </pre>
200    *
201    * <p>NOTE: This method changed in Lang version 2.0.
202    * It no longer trims the CharSequence.
203    * That functionality is available in isBlank().</p>
204    *
205    * @param cs the CharSequence to check, may be null
206    * @return {@code true} if the CharSequence is empty or null
207    * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
208    */
 
209  3755 toggle public static boolean isEmpty(final CharSequence cs) {
210  3755 return cs == null || cs.length() == 0;
211    }
212   
213    /**
214    * <p>Checks if a CharSequence is not empty ("") and not null.</p>
215    *
216    * <pre>
217    * StringUtils.isNotEmpty(null) = false
218    * StringUtils.isNotEmpty("") = false
219    * StringUtils.isNotEmpty(" ") = true
220    * StringUtils.isNotEmpty("bob") = true
221    * StringUtils.isNotEmpty(" bob ") = true
222    * </pre>
223    *
224    * @param cs the CharSequence to check, may be null
225    * @return {@code true} if the CharSequence is not empty and not null
226    * @since 3.0 Changed signature from isNotEmpty(String) to isNotEmpty(CharSequence)
227    */
 
228  82 toggle public static boolean isNotEmpty(final CharSequence cs) {
229  82 return !isEmpty(cs);
230    }
231   
232    /**
233    * <p>Checks if any of the CharSequences are empty ("") or null.</p>
234    *
235    * <pre>
236    * StringUtils.isAnyEmpty(null) = true
237    * StringUtils.isAnyEmpty(null, "foo") = true
238    * StringUtils.isAnyEmpty("", "bar") = true
239    * StringUtils.isAnyEmpty("bob", "") = true
240    * StringUtils.isAnyEmpty(" bob ", null) = true
241    * StringUtils.isAnyEmpty(" ", "bar") = false
242    * StringUtils.isAnyEmpty("foo", "bar") = false
243    * </pre>
244    *
245    * @param css the CharSequences to check, may be null or empty
246    * @return {@code true} if any of the CharSequences are empty or null
247    * @since 3.2
248    */
 
249  16 toggle public static boolean isAnyEmpty(final CharSequence... css) {
250  16 if (ArrayUtils.isEmpty(css)) {
251  2 return false;
252    }
253  14 for (final CharSequence cs : css){
254  22 if (isEmpty(cs)) {
255  10 return true;
256    }
257    }
258  4 return false;
259    }
260   
261    /**
262    * <p>Checks if none of the CharSequences are empty ("") or null.</p>
263    *
264    * <pre>
265    * StringUtils.isNoneEmpty(null) = false
266    * StringUtils.isNoneEmpty(null, "foo") = false
267    * StringUtils.isNoneEmpty("", "bar") = false
268    * StringUtils.isNoneEmpty("bob", "") = false
269    * StringUtils.isNoneEmpty(" bob ", null) = false
270    * StringUtils.isNoneEmpty(new String[] {}) = false
271    * StringUtils.isNoneEmpty(" ", "bar") = true
272    * StringUtils.isNoneEmpty("foo", "bar") = true
273    * </pre>
274    *
275    * @param css the CharSequences to check, may be null or empty
276    * @return {@code true} if none of the CharSequences are empty or null
277    * @since 3.2
278    */
 
279  8 toggle public static boolean isNoneEmpty(final CharSequence... css) {
280  8 return !isAnyEmpty(css);
281    }
282   
283    /**
284    * <p>Checks if all of the CharSequences are empty ("") or null.</p>
285    *
286    * <pre>
287    * StringUtils.isAllEmpty(null) = true
288    * StringUtils.isAllEmpty(null, "") = true
289    * StringUtils.isAllEmpty(new String[] {}) = true
290    * StringUtils.isAllEmpty(null, "foo") = false
291    * StringUtils.isAllEmpty("", "bar") = false
292    * StringUtils.isAllEmpty("bob", "") = false
293    * StringUtils.isAllEmpty(" bob ", null) = false
294    * StringUtils.isAllEmpty(" ", "bar") = false
295    * StringUtils.isAllEmpty("foo", "bar") = false
296    * </pre>
297    *
298    * @param css the CharSequences to check, may be null or empty
299    * @return {@code true} if all of the CharSequences are empty or null
300    * @since 3.6
301    */
 
302  11 toggle public static boolean isAllEmpty(final CharSequence... css) {
303  11 if (ArrayUtils.isEmpty(css)) {
304  3 return true;
305    }
306  8 for (final CharSequence cs : css) {
307  11 if (isNotEmpty(cs)) {
308  6 return false;
309    }
310    }
311  2 return true;
312    }
313   
314    /**
315    * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
316    *
317    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
318    *
319    * <pre>
320    * StringUtils.isBlank(null) = true
321    * StringUtils.isBlank("") = true
322    * StringUtils.isBlank(" ") = true
323    * StringUtils.isBlank("bob") = false
324    * StringUtils.isBlank(" bob ") = false
325    * </pre>
326    *
327    * @param cs the CharSequence to check, may be null
328    * @return {@code true} if the CharSequence is null, empty or whitespace only
329    * @since 2.0
330    * @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
331    */
 
332  671 toggle public static boolean isBlank(final CharSequence cs) {
333  671 int strLen;
334  ? if (cs == null || (strLen = cs.length()) == 0) {
335  62 return true;
336    }
337  770 for (int i = 0; i < strLen; i++) {
338  709 if (Character.isWhitespace(cs.charAt(i)) == false) {
339  548 return false;
340    }
341    }
342  61 return true;
343    }
344   
345    /**
346    * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
347    *
348    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
349    *
350    * <pre>
351    * StringUtils.isNotBlank(null) = false
352    * StringUtils.isNotBlank("") = false
353    * StringUtils.isNotBlank(" ") = false
354    * StringUtils.isNotBlank("bob") = true
355    * StringUtils.isNotBlank(" bob ") = true
356    * </pre>
357    *
358    * @param cs the CharSequence to check, may be null
359    * @return {@code true} if the CharSequence is
360    * not empty and not null and not whitespace only
361    * @since 2.0
362    * @since 3.0 Changed signature from isNotBlank(String) to isNotBlank(CharSequence)
363    */
 
364  305 toggle public static boolean isNotBlank(final CharSequence cs) {
365  305 return !isBlank(cs);
366    }
367   
368    /**
369    * <p>Checks if any of the CharSequences are empty ("") or null or whitespace only.</p>
370    *
371    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
372    *
373    * <pre>
374    * StringUtils.isAnyBlank(null) = true
375    * StringUtils.isAnyBlank(null, "foo") = true
376    * StringUtils.isAnyBlank(null, null) = true
377    * StringUtils.isAnyBlank("", "bar") = true
378    * StringUtils.isAnyBlank("bob", "") = true
379    * StringUtils.isAnyBlank(" bob ", null) = true
380    * StringUtils.isAnyBlank(" ", "bar") = true
381    * StringUtils.isAnyBlank(new String[] {}) = false
382    * StringUtils.isAnyBlank("foo", "bar") = false
383    * </pre>
384    *
385    * @param css the CharSequences to check, may be null or empty
386    * @return {@code true} if any of the CharSequences are empty or null or whitespace only
387    * @since 3.2
388    */
 
389  18 toggle public static boolean isAnyBlank(final CharSequence... css) {
390  18 if (ArrayUtils.isEmpty(css)) {
391  2 return false;
392    }
393  16 for (final CharSequence cs : css){
394  22 if (isBlank(cs)) {
395  14 return true;
396    }
397    }
398  2 return false;
399    }
400   
401    /**
402    * <p>Checks if none of the CharSequences are empty (""), null or whitespace only.</p>
403    *
404    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
405    *
406    * <pre>
407    * StringUtils.isNoneBlank(null) = false
408    * StringUtils.isNoneBlank(null, "foo") = false
409    * StringUtils.isNoneBlank(null, null) = false
410    * StringUtils.isNoneBlank("", "bar") = false
411    * StringUtils.isNoneBlank("bob", "") = false
412    * StringUtils.isNoneBlank(" bob ", null) = false
413    * StringUtils.isNoneBlank(" ", "bar") = false
414    * StringUtils.isNoneBlank(new String[] {}) = false
415    * StringUtils.isNoneBlank("foo", "bar") = true
416    * </pre>
417    *
418    * @param css the CharSequences to check, may be null or empty
419    * @return {@code true} if none of the CharSequences are empty or null or whitespace only
420    * @since 3.2
421    */
 
422  9 toggle public static boolean isNoneBlank(final CharSequence... css) {
423  9 return !isAnyBlank(css);
424    }
425   
426    /**
427    * <p>Checks if all of the CharSequences are empty (""), null or whitespace only.</p>
428    *
429    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
430    *
431    * <pre>
432    * StringUtils.isAllBlank(null) = true
433    * StringUtils.isAllBlank(null, "foo") = false
434    * StringUtils.isAllBlank(null, null) = true
435    * StringUtils.isAllBlank("", "bar") = false
436    * StringUtils.isAllBlank("bob", "") = false
437    * StringUtils.isAllBlank(" bob ", null) = false
438    * StringUtils.isAllBlank(" ", "bar") = false
439    * StringUtils.isAllBlank("foo", "bar") = false
440    * StringUtils.isAllBlank(new String[] {}) = true
441    * </pre>
442    *
443    * @param css the CharSequences to check, may be null or empty
444    * @return {@code true} if all of the CharSequences are empty or null or whitespace only
445    * @since 3.6
446    */
 
447  10 toggle public static boolean isAllBlank(final CharSequence... css) {
448  10 if (ArrayUtils.isEmpty(css)) {
449  1 return true;
450    }
451  9 for (final CharSequence cs : css) {
452  14 if (isNotBlank(cs)) {
453  6 return false;
454    }
455    }
456  3 return true;
457    }
458   
459    // Trim
460    //-----------------------------------------------------------------------
461    /**
462    * <p>Removes control characters (char &lt;= 32) from both
463    * ends of this String, handling {@code null} by returning
464    * {@code null}.</p>
465    *
466    * <p>The String is trimmed using {@link String#trim()}.
467    * Trim removes start and end characters &lt;= 32.
468    * To strip whitespace use {@link #strip(String)}.</p>
469    *
470    * <p>To trim your choice of characters, use the
471    * {@link #strip(String, String)} methods.</p>
472    *
473    * <pre>
474    * StringUtils.trim(null) = null
475    * StringUtils.trim("") = ""
476    * StringUtils.trim(" ") = ""
477    * StringUtils.trim("abc") = "abc"
478    * StringUtils.trim(" abc ") = "abc"
479    * </pre>
480    *
481    * @param str the String to be trimmed, may be null
482    * @return the trimmed string, {@code null} if null String input
483    */
 
484  18 toggle public static String trim(final String str) {
485  18 return str == null ? null : str.trim();
486    }
487   
488    /**
489    * <p>Removes control characters (char &lt;= 32) from both
490    * ends of this String returning {@code null} if the String is
491    * empty ("") after the trim or if it is {@code null}.
492    *
493    * <p>The String is trimmed using {@link String#trim()}.
494    * Trim removes start and end characters &lt;= 32.
495    * To strip whitespace use {@link #stripToNull(String)}.</p>
496    *
497    * <pre>
498    * StringUtils.trimToNull(null) = null
499    * StringUtils.trimToNull("") = null
500    * StringUtils.trimToNull(" ") = null
501    * StringUtils.trimToNull("abc") = "abc"
502    * StringUtils.trimToNull(" abc ") = "abc"
503    * </pre>
504    *
505    * @param str the String to be trimmed, may be null
506    * @return the trimmed String,
507    * {@code null} if only chars &lt;= 32, empty or null String input
508    * @since 2.0
509    */
 
510  9 toggle public static String trimToNull(final String str) {
511  9 final String ts = trim(str);
512  9 return isEmpty(ts) ? null : ts;
513    }
514   
515    /**
516    * <p>Removes control characters (char &lt;= 32) from both
517    * ends of this String returning an empty String ("") if the String
518    * is empty ("") after the trim or if it is {@code null}.
519    *
520    * <p>The String is trimmed using {@link String#trim()}.
521    * Trim removes start and end characters &lt;= 32.
522    * To strip whitespace use {@link #stripToEmpty(String)}.</p>
523    *
524    * <pre>
525    * StringUtils.trimToEmpty(null) = ""
526    * StringUtils.trimToEmpty("") = ""
527    * StringUtils.trimToEmpty(" ") = ""
528    * StringUtils.trimToEmpty("abc") = "abc"
529    * StringUtils.trimToEmpty(" abc ") = "abc"
530    * </pre>
531    *
532    * @param str the String to be trimmed, may be null
533    * @return the trimmed String, or an empty String if {@code null} input
534    * @since 2.0
535    */
 
536  9 toggle public static String trimToEmpty(final String str) {
537  9 return str == null ? EMPTY : str.trim();
538    }
539   
540    /**
541    * <p>Truncates a String. This will turn
542    * "Now is the time for all good men" into "Now is the time for".</p>
543    *
544    * <p>Specifically:</p>
545    * <ul>
546    * <li>If {@code str} is less than {@code maxWidth} characters
547    * long, return it.</li>
548    * <li>Else truncate it to {@code substring(str, 0, maxWidth)}.</li>
549    * <li>If {@code maxWidth} is less than {@code 0}, throw an
550    * {@code IllegalArgumentException}.</li>
551    * <li>In no case will it return a String of length greater than
552    * {@code maxWidth}.</li>
553    * </ul>
554    *
555    * <pre>
556    * StringUtils.truncate(null, 0) = null
557    * StringUtils.truncate(null, 2) = null
558    * StringUtils.truncate("", 4) = ""
559    * StringUtils.truncate("abcdefg", 4) = "abcd"
560    * StringUtils.truncate("abcdefg", 6) = "abcdef"
561    * StringUtils.truncate("abcdefg", 7) = "abcdefg"
562    * StringUtils.truncate("abcdefg", 8) = "abcdefg"
563    * StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
564    * </pre>
565    *
566    * @param str the String to truncate, may be null
567    * @param maxWidth maximum length of result String, must be positive
568    * @return truncated String, {@code null} if null String input
569    * @since 3.5
570    */
 
571  16 toggle public static String truncate(final String str, final int maxWidth) {
572  16 return truncate(str, 0, maxWidth);
573    }
574   
575    /**
576    * <p>Truncates a String. This will turn
577    * "Now is the time for all good men" into "is the time for all".</p>
578    *
579    * <p>Works like {@code truncate(String, int)}, but allows you to specify
580    * a "left edge" offset.
581    *
582    * <p>Specifically:</p>
583    * <ul>
584    * <li>If {@code str} is less than {@code maxWidth} characters
585    * long, return it.</li>
586    * <li>Else truncate it to {@code substring(str, offset, maxWidth)}.</li>
587    * <li>If {@code maxWidth} is less than {@code 0}, throw an
588    * {@code IllegalArgumentException}.</li>
589    * <li>If {@code offset} is less than {@code 0}, throw an
590    * {@code IllegalArgumentException}.</li>
591    * <li>In no case will it return a String of length greater than
592    * {@code maxWidth}.</li>
593    * </ul>
594    *
595    * <pre>
596    * StringUtils.truncate(null, 0, 0) = null
597    * StringUtils.truncate(null, 2, 4) = null
598    * StringUtils.truncate("", 0, 10) = ""
599    * StringUtils.truncate("", 2, 10) = ""
600    * StringUtils.truncate("abcdefghij", 0, 3) = "abc"
601    * StringUtils.truncate("abcdefghij", 5, 6) = "fghij"
602    * StringUtils.truncate("raspberry peach", 10, 15) = "peach"
603    * StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij"
604    * StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException
605    * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij"
606    * StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno"
607    * StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno"
608    * StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk"
609    * StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl"
610    * StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm"
611    * StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn"
612    * StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno"
613    * StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij"
614    * StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh"
615    * StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm"
616    * StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno"
617    * StringUtils.truncate("abcdefghijklmno", 13, 1) = "n"
618    * StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no"
619    * StringUtils.truncate("abcdefghijklmno", 14, 1) = "o"
620    * StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o"
621    * StringUtils.truncate("abcdefghijklmno", 15, 1) = ""
622    * StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = ""
623    * StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = ""
624    * StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException
625    * StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
626    * </pre>
627    *
628    * @param str the String to check, may be null
629    * @param offset left edge of source String
630    * @param maxWidth maximum length of result String, must be positive
631    * @return truncated String, {@code null} if null String input
632    * @since 3.5
633    */
 
634  58 toggle public static String truncate(final String str, final int offset, final int maxWidth) {
635  58 if (offset < 0) {
636  11 throw new IllegalArgumentException("offset cannot be negative");
637    }
638  47 if (maxWidth < 0) {
639  11 throw new IllegalArgumentException("maxWith cannot be negative");
640    }
641  36 if (str == null) {
642  3 return null;
643    }
644  33 if (offset > str.length()) {
645  2 return EMPTY;
646    }
647  31 if (str.length() > maxWidth) {
648  21 final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth;
649  21 return str.substring(offset, ix);
650    }
651  10 return str.substring(offset);
652    }
653   
654    // Stripping
655    //-----------------------------------------------------------------------
656    /**
657    * <p>Strips whitespace from the start and end of a String.</p>
658    *
659    * <p>This is similar to {@link #trim(String)} but removes whitespace.
660    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
661    *
662    * <p>A {@code null} input String returns {@code null}.</p>
663    *
664    * <pre>
665    * StringUtils.strip(null) = null
666    * StringUtils.strip("") = ""
667    * StringUtils.strip(" ") = ""
668    * StringUtils.strip("abc") = "abc"
669    * StringUtils.strip(" abc") = "abc"
670    * StringUtils.strip("abc ") = "abc"
671    * StringUtils.strip(" abc ") = "abc"
672    * StringUtils.strip(" ab c ") = "ab c"
673    * </pre>
674    *
675    * @param str the String to remove whitespace from, may be null
676    * @return the stripped String, {@code null} if null String input
677    */
 
678  5 toggle public static String strip(final String str) {
679  5 return strip(str, null);
680    }
681   
682    /**
683    * <p>Strips whitespace from the start and end of a String returning
684    * {@code null} if the String is empty ("") after the strip.</p>
685    *
686    * <p>This is similar to {@link #trimToNull(String)} but removes whitespace.
687    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
688    *
689    * <pre>
690    * StringUtils.stripToNull(null) = null
691    * StringUtils.stripToNull("") = null
692    * StringUtils.stripToNull(" ") = null
693    * StringUtils.stripToNull("abc") = "abc"
694    * StringUtils.stripToNull(" abc") = "abc"
695    * StringUtils.stripToNull("abc ") = "abc"
696    * StringUtils.stripToNull(" abc ") = "abc"
697    * StringUtils.stripToNull(" ab c ") = "ab c"
698    * </pre>
699    *
700    * @param str the String to be stripped, may be null
701    * @return the stripped String,
702    * {@code null} if whitespace, empty or null String input
703    * @since 2.0
704    */
 
705  6 toggle public static String stripToNull(String str) {
706  6 if (str == null) {
707  1 return null;
708    }
709  5 str = strip(str, null);
710  5 return str.isEmpty() ? null : str;
711    }
712   
713    /**
714    * <p>Strips whitespace from the start and end of a String returning
715    * an empty String if {@code null} input.</p>
716    *
717    * <p>This is similar to {@link #trimToEmpty(String)} but removes whitespace.
718    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
719    *
720    * <pre>
721    * StringUtils.stripToEmpty(null) = ""
722    * StringUtils.stripToEmpty("") = ""
723    * StringUtils.stripToEmpty(" ") = ""
724    * StringUtils.stripToEmpty("abc") = "abc"
725    * StringUtils.stripToEmpty(" abc") = "abc"
726    * StringUtils.stripToEmpty("abc ") = "abc"
727    * StringUtils.stripToEmpty(" abc ") = "abc"
728    * StringUtils.stripToEmpty(" ab c ") = "ab c"
729    * </pre>
730    *
731    * @param str the String to be stripped, may be null
732    * @return the trimmed String, or an empty String if {@code null} input
733    * @since 2.0
734    */
 
735  6 toggle public static String stripToEmpty(final String str) {
736  6 return str == null ? EMPTY : strip(str, null);
737    }
738   
739    /**
740    * <p>Strips any of a set of characters from the start and end of a String.
741    * This is similar to {@link String#trim()} but allows the characters
742    * to be stripped to be controlled.</p>
743    *
744    * <p>A {@code null} input String returns {@code null}.
745    * An empty string ("") input returns the empty string.</p>
746    *
747    * <p>If the stripChars String is {@code null}, whitespace is
748    * stripped as defined by {@link Character#isWhitespace(char)}.
749    * Alternatively use {@link #strip(String)}.</p>
750    *
751    * <pre>
752    * StringUtils.strip(null, *) = null
753    * StringUtils.strip("", *) = ""
754    * StringUtils.strip("abc", null) = "abc"
755    * StringUtils.strip(" abc", null) = "abc"
756    * StringUtils.strip("abc ", null) = "abc"
757    * StringUtils.strip(" abc ", null) = "abc"
758    * StringUtils.strip(" abcyx", "xyz") = " abc"
759    * </pre>
760    *
761    * @param str the String to remove characters from, may be null
762    * @param stripChars the characters to remove, null treated as whitespace
763    * @return the stripped String, {@code null} if null String input
764    */
 
765  45 toggle public static String strip(String str, final String stripChars) {
766  45 if (isEmpty(str)) {
767  13 return str;
768    }
769  32 str = stripStart(str, stripChars);
770  32 return stripEnd(str, stripChars);
771    }
772   
773    /**
774    * <p>Strips any of a set of characters from the start of a String.</p>
775    *
776    * <p>A {@code null} input String returns {@code null}.
777    * An empty string ("") input returns the empty string.</p>
778    *
779    * <p>If the stripChars String is {@code null}, whitespace is
780    * stripped as defined by {@link Character#isWhitespace(char)}.</p>
781    *
782    * <pre>
783    * StringUtils.stripStart(null, *) = null
784    * StringUtils.stripStart("", *) = ""
785    * StringUtils.stripStart("abc", "") = "abc"
786    * StringUtils.stripStart("abc", null) = "abc"
787    * StringUtils.stripStart(" abc", null) = "abc"
788    * StringUtils.stripStart("abc ", null) = "abc "
789    * StringUtils.stripStart(" abc ", null) = "abc "
790    * StringUtils.stripStart("yxabc ", "xyz") = "abc "
791    * </pre>
792    *
793    * @param str the String to remove characters from, may be null
794    * @param stripChars the characters to remove, null treated as whitespace
795    * @return the stripped String, {@code null} if null String input
796    */
 
797  52 toggle public static String stripStart(final String str, final String stripChars) {
798  52 int strLen;
799  ? if (str == null || (strLen = str.length()) == 0) {
800  8 return str;
801    }
802  44 int start = 0;
803  44 if (stripChars == null) {
804  263 while (start != strLen && Character.isWhitespace(str.charAt(start))) {
805  240 start++;
806    }
807  21 } else if (stripChars.isEmpty()) {
808  8 return str;
809    } else {
810  41 while (start != strLen && stripChars.indexOf(str.charAt(start)) != INDEX_NOT_FOUND) {
811  28 start++;
812    }
813    }
814  36 return str.substring(start);
815    }
816   
817    /**
818    * <p>Strips any of a set of characters from the end of a String.</p>
819    *
820    * <p>A {@code null} input String returns {@code null}.
821    * An empty string ("") input returns the empty string.</p>
822    *
823    * <p>If the stripChars String is {@code null}, whitespace is
824    * stripped as defined by {@link Character#isWhitespace(char)}.</p>
825    *
826    * <pre>
827    * StringUtils.stripEnd(null, *) = null
828    * StringUtils.stripEnd("", *) = ""
829    * StringUtils.stripEnd("abc", "") = "abc"
830    * StringUtils.stripEnd("abc", null) = "abc"
831    * StringUtils.stripEnd(" abc", null) = " abc"
832    * StringUtils.stripEnd("abc ", null) = "abc"
833    * StringUtils.stripEnd(" abc ", null) = " abc"
834    * StringUtils.stripEnd(" abcyx", "xyz") = " abc"
835    * StringUtils.stripEnd("120.00", ".0") = "12"
836    * </pre>
837    *
838    * @param str the String to remove characters from, may be null
839    * @param stripChars the set of characters to remove, null treated as whitespace
840    * @return the stripped String, {@code null} if null String input
841    */
 
842  54 toggle public static String stripEnd(final String str, final String stripChars) {
843  54 int end;
844  ? if (str == null || (end = str.length()) == 0) {
845  15 return str;
846    }
847   
848  39 if (stripChars == null) {
849  173 while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
850  156 end--;
851    }
852  22 } else if (stripChars.isEmpty()) {
853  8 return str;
854    } else {
855  45 while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) {
856  31 end--;
857    }
858    }
859  31 return str.substring(0, end);
860    }
861   
862    // StripAll
863    //-----------------------------------------------------------------------
864    /**
865    * <p>Strips whitespace from the start and end of every String in an array.
866    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
867    *
868    * <p>A new array is returned each time, except for length zero.
869    * A {@code null} array will return {@code null}.
870    * An empty array will return itself.
871    * A {@code null} array entry will be ignored.</p>
872    *
873    * <pre>
874    * StringUtils.stripAll(null) = null
875    * StringUtils.stripAll([]) = []
876    * StringUtils.stripAll(["abc", " abc"]) = ["abc", "abc"]
877    * StringUtils.stripAll(["abc ", null]) = ["abc", null]
878    * </pre>
879    *
880    * @param strs the array to remove whitespace from, may be null
881    * @return the stripped Strings, {@code null} if null array input
882    */
 
883  5 toggle public static String[] stripAll(final String... strs) {
884  5 return stripAll(strs, null);
885    }
886   
887    /**
888    * <p>Strips any of a set of characters from the start and end of every
889    * String in an array.</p>
890    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
891    *
892    * <p>A new array is returned each time, except for length zero.
893    * A {@code null} array will return {@code null}.
894    * An empty array will return itself.
895    * A {@code null} array entry will be ignored.
896    * A {@code null} stripChars will strip whitespace as defined by
897    * {@link Character#isWhitespace(char)}.</p>
898    *
899    * <pre>
900    * StringUtils.stripAll(null, *) = null
901    * StringUtils.stripAll([], *) = []
902    * StringUtils.stripAll(["abc", " abc"], null) = ["abc", "abc"]
903    * StringUtils.stripAll(["abc ", null], null) = ["abc", null]
904    * StringUtils.stripAll(["abc ", null], "yz") = ["abc ", null]
905    * StringUtils.stripAll(["yabcz", null], "yz") = ["abc", null]
906    * </pre>
907    *
908    * @param strs the array to remove characters from, may be null
909    * @param stripChars the characters to remove, null treated as whitespace
910    * @return the stripped Strings, {@code null} if null array input
911    */
 
912  8 toggle public static String[] stripAll(final String[] strs, final String stripChars) {
913  8 int strsLen;
914  ? if (strs == null || (strsLen = strs.length) == 0) {
915  4 return strs;
916    }
917  4 final String[] newArr = new String[strsLen];
918  14 for (int i = 0; i < strsLen; i++) {
919  10 newArr[i] = strip(strs[i], stripChars);
920    }
921  4 return newArr;
922    }
923   
924    /**
925    * <p>Removes diacritics (~= accents) from a string. The case will not be altered.</p>
926    * <p>For instance, '&agrave;' will be replaced by 'a'.</p>
927    * <p>Note that ligatures will be left as is.</p>
928    *
929    * <pre>
930    * StringUtils.stripAccents(null) = null
931    * StringUtils.stripAccents("") = ""
932    * StringUtils.stripAccents("control") = "control"
933    * StringUtils.stripAccents("&eacute;clair") = "eclair"
934    * </pre>
935    *
936    * @param input String to be stripped
937    * @return input text with diacritics removed
938    *
939    * @since 3.0
940    */
941    // See also Lucene's ASCIIFoldingFilter (Lucene 2.9) that replaces accented characters by their unaccented equivalent (and uncommitted bug fix: https://issues.apache.org/jira/browse/LUCENE-1343?focusedCommentId=12858907&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#action_12858907).
 
942  7 toggle public static String stripAccents(final String input) {
943  7 if(input == null) {
944  1 return null;
945    }
946  6 final Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");//$NON-NLS-1$
947  6 final StringBuilder decomposed = new StringBuilder(Normalizer.normalize(input, Normalizer.Form.NFD));
948  6 convertRemainingAccentCharacters(decomposed);
949    // Note that this doesn't correctly remove ligatures...
950  6 return pattern.matcher(decomposed).replaceAll(StringUtils.EMPTY);
951    }
952   
 
953  6 toggle private static void convertRemainingAccentCharacters(final StringBuilder decomposed) {
954  109 for (int i = 0; i < decomposed.length(); i++) {
955  103 if (decomposed.charAt(i) == '\u0141') {
956  1 decomposed.deleteCharAt(i);
957  1 decomposed.insert(i, 'L');
958  102 } else if (decomposed.charAt(i) == '\u0142') {
959  1 decomposed.deleteCharAt(i);
960  1 decomposed.insert(i, 'l');
961    }
962    }
963    }
964   
965    // Equals
966    //-----------------------------------------------------------------------
967    /**
968    * <p>Compares two CharSequences, returning {@code true} if they represent
969    * equal sequences of characters.</p>
970    *
971    * <p>{@code null}s are handled without exceptions. Two {@code null}
972    * references are considered to be equal. The comparison is case sensitive.</p>
973    *
974    * <pre>
975    * StringUtils.equals(null, null) = true
976    * StringUtils.equals(null, "abc") = false
977    * StringUtils.equals("abc", null) = false
978    * StringUtils.equals("abc", "abc") = true
979    * StringUtils.equals("abc", "ABC") = false
980    * </pre>
981    *
982    * @see Object#equals(Object)
983    * @param cs1 the first CharSequence, may be {@code null}
984    * @param cs2 the second CharSequence, may be {@code null}
985    * @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
986    * @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
987    */
 
988  296 toggle public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
989  296 if (cs1 == cs2) {
990  61 return true;
991    }
992  235 if (cs1 == null || cs2 == null) {
993  11 return false;
994    }
995  224 if (cs1.length() != cs2.length()) {
996  160 return false;
997    }
998  64 if (cs1 instanceof String && cs2 instanceof String) {
999  54 return cs1.equals(cs2);
1000    }
1001  10 return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
1002    }
1003   
1004    /**
1005    * <p>Compares two CharSequences, returning {@code true} if they represent
1006    * equal sequences of characters, ignoring case.</p>
1007    *
1008    * <p>{@code null}s are handled without exceptions. Two {@code null}
1009    * references are considered equal. Comparison is case insensitive.</p>
1010    *
1011    * <pre>
1012    * StringUtils.equalsIgnoreCase(null, null) = true
1013    * StringUtils.equalsIgnoreCase(null, "abc") = false
1014    * StringUtils.equalsIgnoreCase("abc", null) = false
1015    * StringUtils.equalsIgnoreCase("abc", "abc") = true
1016    * StringUtils.equalsIgnoreCase("abc", "ABC") = true
1017    * </pre>
1018    *
1019    * @param str1 the first CharSequence, may be null
1020    * @param str2 the second CharSequence, may be null
1021    * @return {@code true} if the CharSequence are equal, case insensitive, or
1022    * both {@code null}
1023    * @since 3.0 Changed signature from equalsIgnoreCase(String, String) to equalsIgnoreCase(CharSequence, CharSequence)
1024    */
 
1025  33 toggle public static boolean equalsIgnoreCase(final CharSequence str1, final CharSequence str2) {
1026  33 if (str1 == null || str2 == null) {
1027  11 return str1 == str2;
1028  22 } else if (str1 == str2) {
1029  4 return true;
1030  18 } else if (str1.length() != str2.length()) {
1031  4 return false;
1032    } else {
1033  14 return CharSequenceUtils.regionMatches(str1, true, 0, str2, 0, str1.length());
1034    }
1035    }
1036   
1037    // Compare
1038    //-----------------------------------------------------------------------
1039    /**
1040    * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1041    * <ul>
1042    * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1043    * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1044    * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1045    * </ul>
1046    *
1047    * <p>This is a {@code null} safe version of :</p>
1048    * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1049    *
1050    * <p>{@code null} value is considered less than non-{@code null} value.
1051    * Two {@code null} references are considered equal.</p>
1052    *
1053    * <pre>
1054    * StringUtils.compare(null, null) = 0
1055    * StringUtils.compare(null , "a") &lt; 0
1056    * StringUtils.compare("a", null) &gt; 0
1057    * StringUtils.compare("abc", "abc") = 0
1058    * StringUtils.compare("a", "b") &lt; 0
1059    * StringUtils.compare("b", "a") &gt; 0
1060    * StringUtils.compare("a", "B") &gt; 0
1061    * StringUtils.compare("ab", "abc") &lt; 0
1062    * </pre>
1063    *
1064    * @see #compare(String, String, boolean)
1065    * @see String#compareTo(String)
1066    * @param str1 the String to compare from
1067    * @param str2 the String to compare to
1068    * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
1069    * @since 3.5
1070    */
 
1071  11 toggle public static int compare(final String str1, final String str2) {
1072  11 return compare(str1, str2, true);
1073    }
1074   
1075    /**
1076    * <p>Compare two Strings lexicographically, as per {@link String#compareTo(String)}, returning :</p>
1077    * <ul>
1078    * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1079    * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1080    * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1081    * </ul>
1082    *
1083    * <p>This is a {@code null} safe version of :</p>
1084    * <blockquote><pre>str1.compareTo(str2)</pre></blockquote>
1085    *
1086    * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1087    * Two {@code null} references are considered equal.</p>
1088    *
1089    * <pre>
1090    * StringUtils.compare(null, null, *) = 0
1091    * StringUtils.compare(null , "a", true) &lt; 0
1092    * StringUtils.compare(null , "a", false) &gt; 0
1093    * StringUtils.compare("a", null, true) &gt; 0
1094    * StringUtils.compare("a", null, false) &lt; 0
1095    * StringUtils.compare("abc", "abc", *) = 0
1096    * StringUtils.compare("a", "b", *) &lt; 0
1097    * StringUtils.compare("b", "a", *) &gt; 0
1098    * StringUtils.compare("a", "B", *) &gt; 0
1099    * StringUtils.compare("ab", "abc", *) &lt; 0
1100    * </pre>
1101    *
1102    * @see String#compareTo(String)
1103    * @param str1 the String to compare from
1104    * @param str2 the String to compare to
1105    * @param nullIsLess whether consider {@code null} value less than non-{@code null} value
1106    * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2}
1107    * @since 3.5
1108    */
 
1109  24 toggle public static int compare(final String str1, final String str2, final boolean nullIsLess) {
1110  24 if (str1 == str2) {
1111  4 return 0;
1112    }
1113  20 if (str1 == null) {
1114  3 return nullIsLess ? -1 : 1;
1115    }
1116  17 if (str2 == null) {
1117  3 return nullIsLess ? 1 : - 1;
1118    }
1119  14 return str1.compareTo(str2);
1120    }
1121   
1122    /**
1123    * <p>Compare two Strings lexicographically, ignoring case differences,
1124    * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1125    * <ul>
1126    * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1127    * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1128    * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1129    * </ul>
1130    *
1131    * <p>This is a {@code null} safe version of :</p>
1132    * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1133    *
1134    * <p>{@code null} value is considered less than non-{@code null} value.
1135    * Two {@code null} references are considered equal.
1136    * Comparison is case insensitive.</p>
1137    *
1138    * <pre>
1139    * StringUtils.compareIgnoreCase(null, null) = 0
1140    * StringUtils.compareIgnoreCase(null , "a") &lt; 0
1141    * StringUtils.compareIgnoreCase("a", null) &gt; 0
1142    * StringUtils.compareIgnoreCase("abc", "abc") = 0
1143    * StringUtils.compareIgnoreCase("abc", "ABC") = 0
1144    * StringUtils.compareIgnoreCase("a", "b") &lt; 0
1145    * StringUtils.compareIgnoreCase("b", "a") &gt; 0
1146    * StringUtils.compareIgnoreCase("a", "B") &lt; 0
1147    * StringUtils.compareIgnoreCase("A", "b") &lt; 0
1148    * StringUtils.compareIgnoreCase("ab", "ABC") &lt; 0
1149    * </pre>
1150    *
1151    * @see #compareIgnoreCase(String, String, boolean)
1152    * @see String#compareToIgnoreCase(String)
1153    * @param str1 the String to compare from
1154    * @param str2 the String to compare to
1155    * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1156    * ignoring case differences.
1157    * @since 3.5
1158    */
 
1159  13 toggle public static int compareIgnoreCase(final String str1, final String str2) {
1160  13 return compareIgnoreCase(str1, str2, true);
1161    }
1162   
1163    /**
1164    * <p>Compare two Strings lexicographically, ignoring case differences,
1165    * as per {@link String#compareToIgnoreCase(String)}, returning :</p>
1166    * <ul>
1167    * <li>{@code int = 0}, if {@code str1} is equal to {@code str2} (or both {@code null})</li>
1168    * <li>{@code int < 0}, if {@code str1} is less than {@code str2}</li>
1169    * <li>{@code int > 0}, if {@code str1} is greater than {@code str2}</li>
1170    * </ul>
1171    *
1172    * <p>This is a {@code null} safe version of :</p>
1173    * <blockquote><pre>str1.compareToIgnoreCase(str2)</pre></blockquote>
1174    *
1175    * <p>{@code null} inputs are handled according to the {@code nullIsLess} parameter.
1176    * Two {@code null} references are considered equal.
1177    * Comparison is case insensitive.</p>
1178    *
1179    * <pre>
1180    * StringUtils.compareIgnoreCase(null, null, *) = 0
1181    * StringUtils.compareIgnoreCase(null , "a", true) &lt; 0
1182    * StringUtils.compareIgnoreCase(null , "a", false) &gt; 0
1183    * StringUtils.compareIgnoreCase("a", null, true) &gt; 0
1184    * StringUtils.compareIgnoreCase("a", null, false) &lt; 0
1185    * StringUtils.compareIgnoreCase("abc", "abc", *) = 0
1186    * StringUtils.compareIgnoreCase("abc", "ABC", *) = 0
1187    * StringUtils.compareIgnoreCase("a", "b", *) &lt; 0
1188    * StringUtils.compareIgnoreCase("b", "a", *) &gt; 0
1189    * StringUtils.compareIgnoreCase("a", "B", *) &lt; 0
1190    * StringUtils.compareIgnoreCase("A", "b", *) &lt; 0
1191    * StringUtils.compareIgnoreCase("ab", "abc", *) &lt; 0
1192    * </pre>
1193    *
1194    * @see String#compareToIgnoreCase(String)
1195    * @param str1 the String to compare from
1196    * @param str2 the String to compare to
1197    * @param nullIsLess whether consider {@code null} value less than non-{@code null} value
1198    * @return &lt; 0, 0, &gt; 0, if {@code str1} is respectively less, equal ou greater than {@code str2},
1199    * ignoring case differences.
1200    * @since 3.5
1201    */
 
1202  28 toggle public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) {
1203  28 if (str1 == str2) {
1204  4 return 0;
1205    }
1206  24 if (str1 == null) {
1207  3 return nullIsLess ? -1 : 1;
1208    }
1209  21 if (str2 == null) {
1210  3 return nullIsLess ? 1 : - 1;
1211    }
1212  18 return str1.compareToIgnoreCase(str2);
1213    }
1214   
1215    /**
1216    * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1217    * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>.</p>
1218    *
1219    * <pre>
1220    * StringUtils.equalsAny(null, (CharSequence[]) null) = false
1221    * StringUtils.equalsAny(null, null, null) = true
1222    * StringUtils.equalsAny(null, "abc", "def") = false
1223    * StringUtils.equalsAny("abc", null, "def") = false
1224    * StringUtils.equalsAny("abc", "abc", "def") = true
1225    * StringUtils.equalsAny("abc", "ABC", "DEF") = false
1226    * </pre>
1227    *
1228    * @param string to compare, may be {@code null}.
1229    * @param searchStrings a vararg of strings, may be {@code null}.
1230    * @return {@code true} if the string is equal (case-sensitive) to any other element of <code>searchStrings</code>;
1231    * {@code false} if <code>searchStrings</code> is null or contains no matches.
1232    * @since 3.5
1233    */
 
1234  20 toggle public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) {
1235  20 if (ArrayUtils.isNotEmpty(searchStrings)) {
1236  17 for (final CharSequence next : searchStrings) {
1237  26 if (equals(string, next)) {
1238  6 return true;
1239    }
1240    }
1241    }
1242  14 return false;
1243    }
1244   
1245   
1246    /**
1247    * <p>Compares given <code>string</code> to a CharSequences vararg of <code>searchStrings</code>,
1248    * returning {@code true} if the <code>string</code> is equal to any of the <code>searchStrings</code>, ignoring case.</p>
1249    *
1250    * <pre>
1251    * StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
1252    * StringUtils.equalsAnyIgnoreCase(null, null, null) = true
1253    * StringUtils.equalsAnyIgnoreCase(null, "abc", "def") = false
1254    * StringUtils.equalsAnyIgnoreCase("abc", null, "def") = false
1255    * StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
1256    * StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true
1257    * </pre>
1258    *
1259    * @param string to compare, may be {@code null}.
1260    * @param searchStrings a vararg of strings, may be {@code null}.
1261    * @return {@code true} if the string is equal (case-insensitive) to any other element of <code>searchStrings</code>;
1262    * {@code false} if <code>searchStrings</code> is null or contains no matches.
1263    * @since 3.5
1264    */
 
1265  19 toggle public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) {
1266  19 if (ArrayUtils.isNotEmpty(searchStrings)) {
1267  16 for (final CharSequence next : searchStrings) {
1268  24 if (equalsIgnoreCase(string, next)) {
1269  9 return true;
1270    }
1271    }
1272    }
1273  10 return false;
1274    }
1275   
1276    // IndexOf
1277    //-----------------------------------------------------------------------
1278    /**
1279    * Returns the index within <code>seq</code> of the first occurrence of
1280    * the specified character. If a character with value
1281    * <code>searchChar</code> occurs in the character sequence represented by
1282    * <code>seq</code> <code>CharSequence</code> object, then the index (in Unicode
1283    * code units) of the first such occurrence is returned. For
1284    * values of <code>searchChar</code> in the range from 0 to 0xFFFF
1285    * (inclusive), this is the smallest value <i>k</i> such that:
1286    * <blockquote><pre>
1287    * this.charAt(<i>k</i>) == searchChar
1288    * </pre></blockquote>
1289    * is true. For other values of <code>searchChar</code>, it is the
1290    * smallest value <i>k</i> such that:
1291    * <blockquote><pre>
1292    * this.codePointAt(<i>k</i>) == searchChar
1293    * </pre></blockquote>
1294    * is true. In either case, if no such character occurs in <code>seq</code>,
1295    * then {@code INDEX_NOT_FOUND (-1)} is returned.
1296    *
1297    * <p>Furthermore, a {@code null} or empty ("") CharSequence will
1298    * return {@code INDEX_NOT_FOUND (-1)}.</p>
1299    *
1300    * <pre>
1301    * StringUtils.indexOf(null, *) = -1
1302    * StringUtils.indexOf("", *) = -1
1303    * StringUtils.indexOf("aabaabaa", 'a') = 0
1304    * StringUtils.indexOf("aabaabaa", 'b') = 2
1305    * </pre>
1306    *
1307    * @param seq the CharSequence to check, may be null
1308    * @param searchChar the character to find
1309    * @return the first index of the search character,
1310    * -1 if no match or {@code null} string input
1311    * @since 2.0
1312    * @since 3.0 Changed signature from indexOf(String, int) to indexOf(CharSequence, int)
1313    * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1314    */
 
1315  5 toggle public static int indexOf(final CharSequence seq, final int searchChar) {
1316  5 if (isEmpty(seq)) {
1317  2 return INDEX_NOT_FOUND;
1318    }
1319  3 return CharSequenceUtils.indexOf(seq, searchChar, 0);
1320    }
1321   
1322    /**
1323    *
1324    * Returns the index within <code>seq</code> of the first occurrence of the
1325    * specified character, starting the search at the specified index.
1326    * <p>
1327    * If a character with value <code>searchChar</code> occurs in the
1328    * character sequence represented by the <code>seq</code> <code>CharSequence</code>
1329    * object at an index no smaller than <code>startPos</code>, then
1330    * the index of the first such occurrence is returned. For values
1331    * of <code>searchChar</code> in the range from 0 to 0xFFFF (inclusive),
1332    * this is the smallest value <i>k</i> such that:
1333    * <blockquote><pre>
1334    * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1335    * </pre></blockquote>
1336    * is true. For other values of <code>searchChar</code>, it is the
1337    * smallest value <i>k</i> such that:
1338    * <blockquote><pre>
1339    * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= startPos)
1340    * </pre></blockquote>
1341    * is true. In either case, if no such character occurs in <code>seq</code>
1342    * at or after position <code>startPos</code>, then
1343    * <code>-1</code> is returned.
1344    *
1345    * <p>
1346    * There is no restriction on the value of <code>startPos</code>. If it
1347    * is negative, it has the same effect as if it were zero: this entire
1348    * string may be searched. If it is greater than the length of this
1349    * string, it has the same effect as if it were equal to the length of
1350    * this string: {@code (INDEX_NOT_FOUND) -1} is returned. Furthermore, a
1351    * {@code null} or empty ("") CharSequence will
1352    * return {@code (INDEX_NOT_FOUND) -1}.
1353    *
1354    * <p>All indices are specified in <code>char</code> values
1355    * (Unicode code units).
1356    *
1357    * <pre>
1358    * StringUtils.indexOf(null, *, *) = -1
1359    * StringUtils.indexOf("", *, *) = -1
1360    * StringUtils.indexOf("aabaabaa", 'b', 0) = 2
1361    * StringUtils.indexOf("aabaabaa", 'b', 3) = 5
1362    * StringUtils.indexOf("aabaabaa", 'b', 9) = -1
1363    * StringUtils.indexOf("aabaabaa", 'b', -1) = 2
1364    * </pre>
1365    *
1366    * @param seq the CharSequence to check, may be null
1367    * @param searchChar the character to find
1368    * @param startPos the start position, negative treated as zero
1369    * @return the first index of the search character (always &ge; startPos),
1370    * -1 if no match or {@code null} string input
1371    * @since 2.0
1372    * @since 3.0 Changed signature from indexOf(String, int, int) to indexOf(CharSequence, int, int)
1373    * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1374    */
 
1375  20 toggle public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) {
1376  20 if (isEmpty(seq)) {
1377  4 return INDEX_NOT_FOUND;
1378    }
1379  16 return CharSequenceUtils.indexOf(seq, searchChar, startPos);
1380    }
1381   
1382    /**
1383    * <p>Finds the first index within a CharSequence, handling {@code null}.
1384    * This method uses {@link String#indexOf(String, int)} if possible.</p>
1385    *
1386    * <p>A {@code null} CharSequence will return {@code -1}.</p>
1387    *
1388    * <pre>
1389    * StringUtils.indexOf(null, *) = -1
1390    * StringUtils.indexOf(*, null) = -1
1391    * StringUtils.indexOf("", "") = 0
1392    * StringUtils.indexOf("", *) = -1 (except when * = "")
1393    * StringUtils.indexOf("aabaabaa", "a") = 0
1394    * StringUtils.indexOf("aabaabaa", "b") = 2
1395    * StringUtils.indexOf("aabaabaa", "ab") = 1
1396    * StringUtils.indexOf("aabaabaa", "") = 0
1397    * </pre>
1398    *
1399    * @param seq the CharSequence to check, may be null
1400    * @param searchSeq the CharSequence to find, may be null
1401    * @return the first index of the search CharSequence,
1402    * -1 if no match or {@code null} string input
1403    * @since 2.0
1404    * @since 3.0 Changed signature from indexOf(String, String) to indexOf(CharSequence, CharSequence)
1405    */
 
1406  8 toggle public static int indexOf(final CharSequence seq, final CharSequence searchSeq) {
1407  8 if (seq == null || searchSeq == null) {
1408  2 return INDEX_NOT_FOUND;
1409    }
1410  6 return CharSequenceUtils.indexOf(seq, searchSeq, 0);
1411    }
1412   
1413    /**
1414    * <p>Finds the first index within a CharSequence, handling {@code null}.
1415    * This method uses {@link String#indexOf(String, int)} if possible.</p>
1416    *
1417    * <p>A {@code null} CharSequence will return {@code -1}.
1418    * A negative start position is treated as zero.
1419    * An empty ("") search CharSequence always matches.
1420    * A start position greater than the string length only matches
1421    * an empty search CharSequence.</p>
1422    *
1423    * <pre>
1424    * StringUtils.indexOf(null, *, *) = -1
1425    * StringUtils.indexOf(*, null, *) = -1
1426    * StringUtils.indexOf("", "", 0) = 0
1427    * StringUtils.indexOf("", *, 0) = -1 (except when * = "")
1428    * StringUtils.indexOf("aabaabaa", "a", 0) = 0
1429    * StringUtils.indexOf("aabaabaa", "b", 0) = 2
1430    * StringUtils.indexOf("aabaabaa", "ab", 0) = 1
1431    * StringUtils.indexOf("aabaabaa", "b", 3) = 5
1432    * StringUtils.indexOf("aabaabaa", "b", 9) = -1
1433    * StringUtils.indexOf("aabaabaa", "b", -1) = 2
1434    * StringUtils.indexOf("aabaabaa", "", 2) = 2
1435    * StringUtils.indexOf("abc", "", 9) = 3
1436    * </pre>
1437    *
1438    * @param seq the CharSequence to check, may be null
1439    * @param searchSeq the CharSequence to find, may be null
1440    * @param startPos the start position, negative treated as zero
1441    * @return the first index of the search CharSequence (always &ge; startPos),
1442    * -1 if no match or {@code null} string input
1443    * @since 2.0
1444    * @since 3.0 Changed signature from indexOf(String, String, int) to indexOf(CharSequence, CharSequence, int)
1445    */
 
1446  25 toggle public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1447  25 if (seq == null || searchSeq == null) {
1448  6 return INDEX_NOT_FOUND;
1449    }
1450  19 return CharSequenceUtils.indexOf(seq, searchSeq, startPos);
1451    }
1452   
1453    /**
1454    * <p>Finds the n-th index within a CharSequence, handling {@code null}.
1455    * This method uses {@link String#indexOf(String)} if possible.</p>
1456    * <p><b>Note:</b> The code starts looking for a match at the start of the target,
1457    * incrementing the starting index by one after each successful match
1458    * (unless {@code searchStr} is an empty string in which case the position
1459    * is never incremented and {@code 0} is returned immediately).
1460    * This means that matches may overlap.</p>
1461    * <p>A {@code null} CharSequence will return {@code -1}.</p>
1462    *
1463    * <pre>
1464    * StringUtils.ordinalIndexOf(null, *, *) = -1
1465    * StringUtils.ordinalIndexOf(*, null, *) = -1
1466    * StringUtils.ordinalIndexOf("", "", *) = 0
1467    * StringUtils.ordinalIndexOf("aabaabaa", "a", 1) = 0
1468    * StringUtils.ordinalIndexOf("aabaabaa", "a", 2) = 1
1469    * StringUtils.ordinalIndexOf("aabaabaa", "b", 1) = 2
1470    * StringUtils.ordinalIndexOf("aabaabaa", "b", 2) = 5
1471    * StringUtils.ordinalIndexOf("aabaabaa", "ab", 1) = 1
1472    * StringUtils.ordinalIndexOf("aabaabaa", "ab", 2) = 4
1473    * StringUtils.ordinalIndexOf("aabaabaa", "", 1) = 0
1474    * StringUtils.ordinalIndexOf("aabaabaa", "", 2) = 0
1475    * </pre>
1476    *
1477    * <p>Matches may overlap:</p>
1478    * <pre>
1479    * StringUtils.ordinalIndexOf("ababab","aba", 1) = 0
1480    * StringUtils.ordinalIndexOf("ababab","aba", 2) = 2
1481    * StringUtils.ordinalIndexOf("ababab","aba", 3) = -1
1482    *
1483    * StringUtils.ordinalIndexOf("abababab", "abab", 1) = 0
1484    * StringUtils.ordinalIndexOf("abababab", "abab", 2) = 2
1485    * StringUtils.ordinalIndexOf("abababab", "abab", 3) = 4
1486    * StringUtils.ordinalIndexOf("abababab", "abab", 4) = -1
1487    * </pre>
1488    *
1489    * <p>Note that 'head(CharSequence str, int n)' may be implemented as: </p>
1490    *
1491    * <pre>
1492    * str.substring(0, lastOrdinalIndexOf(str, "\n", n))
1493    * </pre>
1494    *
1495    * @param str the CharSequence to check, may be null
1496    * @param searchStr the CharSequence to find, may be null
1497    * @param ordinal the n-th {@code searchStr} to find
1498    * @return the n-th index of the search CharSequence,
1499    * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1500    * @since 2.1
1501    * @since 3.0 Changed signature from ordinalIndexOf(String, String, int) to ordinalIndexOf(CharSequence, CharSequence, int)
1502    */
 
1503  76 toggle public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1504  76 return ordinalIndexOf(str, searchStr, ordinal, false);
1505    }
1506   
1507    /**
1508    * <p>Finds the n-th index within a String, handling {@code null}.
1509    * This method uses {@link String#indexOf(String)} if possible.</p>
1510    * <p>Note that matches may overlap<p>
1511    *
1512    * <p>A {@code null} CharSequence will return {@code -1}.</p>
1513    *
1514    * @param str the CharSequence to check, may be null
1515    * @param searchStr the CharSequence to find, may be null
1516    * @param ordinal the n-th {@code searchStr} to find, overlapping matches are allowed.
1517    * @param lastIndex true if lastOrdinalIndexOf() otherwise false if ordinalIndexOf()
1518    * @return the n-th index of the search CharSequence,
1519    * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1520    */
1521    // Shared code between ordinalIndexOf(String,String,int) and lastOrdinalIndexOf(String,String,int)
 
1522  87 toggle private static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal, final boolean lastIndex) {
1523  87 if (str == null || searchStr == null || ordinal <= 0) {
1524  30 return INDEX_NOT_FOUND;
1525    }
1526  57 if (searchStr.length() == 0) {
1527  9 return lastIndex ? str.length() : 0;
1528    }
1529  48 int found = 0;
1530    // set the initial index beyond the end of the string
1531    // this is to allow for the initial index decrement/increment
1532  48 int index = lastIndex ? str.length() : INDEX_NOT_FOUND;
1533  48 do {
1534  142 if (lastIndex) {
1535  9 index = CharSequenceUtils.lastIndexOf(str, searchStr, index - 1); // step backwards thru string
1536    } else {
1537  133 index = CharSequenceUtils.indexOf(str, searchStr, index + 1); // step forwards through string
1538    }
1539  142 if (index < 0) {
1540  7 return index;
1541    }
1542  135 found++;
1543  135 } while (found < ordinal);
1544  41 return index;
1545    }
1546   
1547    /**
1548    * <p>Case in-sensitive find of the first index within a CharSequence.</p>
1549    *
1550    * <p>A {@code null} CharSequence will return {@code -1}.
1551    * A negative start position is treated as zero.
1552    * An empty ("") search CharSequence always matches.
1553    * A start position greater than the string length only matches
1554    * an empty search CharSequence.</p>
1555    *
1556    * <pre>
1557    * StringUtils.indexOfIgnoreCase(null, *) = -1
1558    * StringUtils.indexOfIgnoreCase(*, null) = -1
1559    * StringUtils.indexOfIgnoreCase("", "") = 0
1560    * StringUtils.indexOfIgnoreCase("aabaabaa", "a") = 0
1561    * StringUtils.indexOfIgnoreCase("aabaabaa", "b") = 2
1562    * StringUtils.indexOfIgnoreCase("aabaabaa", "ab") = 1
1563    * </pre>
1564    *
1565    * @param str the CharSequence to check, may be null
1566    * @param searchStr the CharSequence to find, may be null
1567    * @return the first index of the search CharSequence,
1568    * -1 if no match or {@code null} string input
1569    * @since 2.5
1570    * @since 3.0 Changed signature from indexOfIgnoreCase(String, String) to indexOfIgnoreCase(CharSequence, CharSequence)
1571    */
 
1572  11 toggle public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1573  11 return indexOfIgnoreCase(str, searchStr, 0);
1574    }
1575   
1576    /**
1577    * <p>Case in-sensitive find of the first index within a CharSequence
1578    * from the specified position.</p>
1579    *
1580    * <p>A {@code null} CharSequence will return {@code -1}.
1581    * A negative start position is treated as zero.
1582    * An empty ("") search CharSequence always matches.
1583    * A start position greater than the string length only matches
1584    * an empty search CharSequence.</p>
1585    *
1586    * <pre>
1587    * StringUtils.indexOfIgnoreCase(null, *, *) = -1
1588    * StringUtils.indexOfIgnoreCase(*, null, *) = -1
1589    * StringUtils.indexOfIgnoreCase("", "", 0) = 0
1590    * StringUtils.indexOfIgnoreCase("aabaabaa", "A", 0) = 0
1591    * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 0) = 2
1592    * StringUtils.indexOfIgnoreCase("aabaabaa", "AB", 0) = 1
1593    * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 3) = 5
1594    * StringUtils.indexOfIgnoreCase("aabaabaa", "B", 9) = -1
1595    * StringUtils.indexOfIgnoreCase("aabaabaa", "B", -1) = 2
1596    * StringUtils.indexOfIgnoreCase("aabaabaa", "", 2) = 2
1597    * StringUtils.indexOfIgnoreCase("abc", "", 9) = -1
1598    * </pre>
1599    *
1600    * @param str the CharSequence to check, may be null
1601    * @param searchStr the CharSequence to find, may be null
1602    * @param startPos the start position, negative treated as zero
1603    * @return the first index of the search CharSequence (always &ge; startPos),
1604    * -1 if no match or {@code null} string input
1605    * @since 2.5
1606    * @since 3.0 Changed signature from indexOfIgnoreCase(String, String, int) to indexOfIgnoreCase(CharSequence, CharSequence, int)
1607    */
 
1608  26 toggle public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1609  26 if (str == null || searchStr == null) {
1610  3 return INDEX_NOT_FOUND;
1611    }
1612  23 if (startPos < 0) {
1613  1 startPos = 0;
1614    }
1615  23 final int endLimit = str.length() - searchStr.length() + 1;
1616  23 if (startPos > endLimit) {
1617  2 return INDEX_NOT_FOUND;
1618    }
1619  21 if (searchStr.length() == 0) {
1620  3 return startPos;
1621    }
1622  32 for (int i = startPos; i < endLimit; i++) {
1623  27 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1624  13 return i;
1625    }
1626    }
1627  5 return INDEX_NOT_FOUND;
1628    }
1629   
1630    // LastIndexOf
1631    //-----------------------------------------------------------------------
1632    /**
1633    * Returns the index within <code>seq</code> of the last occurrence of
1634    * the specified character. For values of <code>searchChar</code> in the
1635    * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
1636    * units) returned is the largest value <i>k</i> such that:
1637    * <blockquote><pre>
1638    * this.charAt(<i>k</i>) == searchChar
1639    * </pre></blockquote>
1640    * is true. For other values of <code>searchChar</code>, it is the
1641    * largest value <i>k</i> such that:
1642    * <blockquote><pre>
1643    * this.codePointAt(<i>k</i>) == searchChar
1644    * </pre></blockquote>
1645    * is true. In either case, if no such character occurs in this
1646    * string, then <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1647    * <code>CharSequence</code> will return {@code -1}. The
1648    * <code>seq</code> <code>CharSequence</code> object is searched backwards
1649    * starting at the last character.
1650    *
1651    * <pre>
1652    * StringUtils.lastIndexOf(null, *) = -1
1653    * StringUtils.lastIndexOf("", *) = -1
1654    * StringUtils.lastIndexOf("aabaabaa", 'a') = 7
1655    * StringUtils.lastIndexOf("aabaabaa", 'b') = 5
1656    * </pre>
1657    *
1658    * @param seq the <code>CharSequence</code> to check, may be null
1659    * @param searchChar the character to find
1660    * @return the last index of the search character,
1661    * -1 if no match or {@code null} string input
1662    * @since 2.0
1663    * @since 3.0 Changed signature from lastIndexOf(String, int) to lastIndexOf(CharSequence, int)
1664    * @since 3.6 Updated {@link CharSequenceUtils} call to behave more like <code>String</code>
1665    */
 
1666  5 toggle public static int lastIndexOf(final CharSequence seq, final int searchChar) {
1667  5 if (isEmpty(seq)) {
1668  2 return INDEX_NOT_FOUND;
1669    }
1670  3 return CharSequenceUtils.lastIndexOf(seq, searchChar, seq.length());
1671    }
1672   
1673    /**
1674    * Returns the index within <code>seq</code> of the last occurrence of
1675    * the specified character, searching backward starting at the
1676    * specified index. For values of <code>searchChar</code> in the range
1677    * from 0 to 0xFFFF (inclusive), the index returned is the largest
1678    * value <i>k</i> such that:
1679    * <blockquote><pre>
1680    * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1681    * </pre></blockquote>
1682    * is true. For other values of <code>searchChar</code>, it is the
1683    * largest value <i>k</i> such that:
1684    * <blockquote><pre>
1685    * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &lt;= startPos)
1686    * </pre></blockquote>
1687    * is true. In either case, if no such character occurs in <code>seq</code>
1688    * at or before position <code>startPos</code>, then
1689    * <code>-1</code> is returned. Furthermore, a {@code null} or empty ("")
1690    * <code>CharSequence</code> will return {@code -1}. A start position greater
1691    * than the string length searches the whole string.
1692    * The search starts at the <code>startPos</code> and works backwards;
1693    * matches starting after the start position are ignored.
1694    *
1695    * <p>All indices are specified in <code>char</code> values
1696    * (Unicode code units).
1697    *
1698    * <pre>
1699    * StringUtils.lastIndexOf(null, *, *) = -1
1700    * StringUtils.lastIndexOf("", *, *) = -1
1701    * StringUtils.lastIndexOf("aabaabaa", 'b', 8) = 5
1702    * StringUtils.lastIndexOf("aabaabaa", 'b', 4) = 2
1703    * StringUtils.lastIndexOf("aabaabaa", 'b', 0) = -1
1704    * StringUtils.lastIndexOf("aabaabaa", 'b', 9) = 5
1705    * StringUtils.lastIndexOf("aabaabaa", 'b', -1) = -1
1706    * StringUtils.lastIndexOf("aabaabaa", 'a', 0) = 0
1707    * </pre>
1708    *
1709    * @param seq the CharSequence to check, may be null
1710    * @param searchChar the character to find
1711    * @param startPos the start position
1712    * @return the last index of the search character (always &le; startPos),
1713    * -1 if no match or {@code null} string input
1714    * @since 2.0
1715    * @since 3.0 Changed signature from lastIndexOf(String, int, int) to lastIndexOf(CharSequence, int, int)
1716    */
 
1717  21 toggle public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) {
1718  21 if (isEmpty(seq)) {
1719  4 return INDEX_NOT_FOUND;
1720    }
1721  17 return CharSequenceUtils.lastIndexOf(seq, searchChar, startPos);
1722    }
1723   
1724    /**
1725    * <p>Finds the last index within a CharSequence, handling {@code null}.
1726    * This method uses {@link String#lastIndexOf(String)} if possible.</p>
1727    *
1728    * <p>A {@code null} CharSequence will return {@code -1}.</p>
1729    *
1730    * <pre>
1731    * StringUtils.lastIndexOf(null, *) = -1
1732    * StringUtils.lastIndexOf(*, null) = -1
1733    * StringUtils.lastIndexOf("", "") = 0
1734    * StringUtils.lastIndexOf("aabaabaa", "a") = 7
1735    * StringUtils.lastIndexOf("aabaabaa", "b") = 5
1736    * StringUtils.lastIndexOf("aabaabaa", "ab") = 4
1737    * StringUtils.lastIndexOf("aabaabaa", "") = 8
1738    * </pre>
1739    *
1740    * @param seq the CharSequence to check, may be null
1741    * @param searchSeq the CharSequence to find, may be null
1742    * @return the last index of the search String,
1743    * -1 if no match or {@code null} string input
1744    * @since 2.0
1745    * @since 3.0 Changed signature from lastIndexOf(String, String) to lastIndexOf(CharSequence, CharSequence)
1746    */
 
1747  9 toggle public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) {
1748  9 if (seq == null || searchSeq == null) {
1749  2 return INDEX_NOT_FOUND;
1750    }
1751  7 return CharSequenceUtils.lastIndexOf(seq, searchSeq, seq.length());
1752    }
1753   
1754    /**
1755    * <p>Finds the n-th last index within a String, handling {@code null}.
1756    * This method uses {@link String#lastIndexOf(String)}.</p>
1757    *
1758    * <p>A {@code null} String will return {@code -1}.</p>
1759    *
1760    * <pre>
1761    * StringUtils.lastOrdinalIndexOf(null, *, *) = -1
1762    * StringUtils.lastOrdinalIndexOf(*, null, *) = -1
1763    * StringUtils.lastOrdinalIndexOf("", "", *) = 0
1764    * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 1) = 7
1765    * StringUtils.lastOrdinalIndexOf("aabaabaa", "a", 2) = 6
1766    * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 1) = 5
1767    * StringUtils.lastOrdinalIndexOf("aabaabaa", "b", 2) = 2
1768    * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 1) = 4
1769    * StringUtils.lastOrdinalIndexOf("aabaabaa", "ab", 2) = 1
1770    * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 1) = 8
1771    * StringUtils.lastOrdinalIndexOf("aabaabaa", "", 2) = 8
1772    * </pre>
1773    *
1774    * <p>Note that 'tail(CharSequence str, int n)' may be implemented as: </p>
1775    *
1776    * <pre>
1777    * str.substring(lastOrdinalIndexOf(str, "\n", n) + 1)
1778    * </pre>
1779    *
1780    * @param str the CharSequence to check, may be null
1781    * @param searchStr the CharSequence to find, may be null
1782    * @param ordinal the n-th last {@code searchStr} to find
1783    * @return the n-th last index of the search CharSequence,
1784    * {@code -1} ({@code INDEX_NOT_FOUND}) if no match or {@code null} string input
1785    * @since 2.5
1786    * @since 3.0 Changed signature from lastOrdinalIndexOf(String, String, int) to lastOrdinalIndexOf(CharSequence, CharSequence, int)
1787    */
 
1788  11 toggle public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) {
1789  11 return ordinalIndexOf(str, searchStr, ordinal, true);
1790    }
1791   
1792    /**
1793    * <p>Finds the last index within a CharSequence, handling {@code null}.
1794    * This method uses {@link String#lastIndexOf(String, int)} if possible.</p>
1795    *
1796    * <p>A {@code null} CharSequence will return {@code -1}.
1797    * A negative start position returns {@code -1}.
1798    * An empty ("") search CharSequence always matches unless the start position is negative.
1799    * A start position greater than the string length searches the whole string.
1800    * The search starts at the startPos and works backwards; matches starting after the start
1801    * position are ignored.
1802    * </p>
1803    *
1804    * <pre>
1805    * StringUtils.lastIndexOf(null, *, *) = -1
1806    * StringUtils.lastIndexOf(*, null, *) = -1
1807    * StringUtils.lastIndexOf("aabaabaa", "a", 8) = 7
1808    * StringUtils.lastIndexOf("aabaabaa", "b", 8) = 5
1809    * StringUtils.lastIndexOf("aabaabaa", "ab", 8) = 4
1810    * StringUtils.lastIndexOf("aabaabaa", "b", 9) = 5
1811    * StringUtils.lastIndexOf("aabaabaa", "b", -1) = -1
1812    * StringUtils.lastIndexOf("aabaabaa", "a", 0) = 0
1813    * StringUtils.lastIndexOf("aabaabaa", "b", 0) = -1
1814    * StringUtils.lastIndexOf("aabaabaa", "b", 1) = -1
1815    * StringUtils.lastIndexOf("aabaabaa", "b", 2) = 2
1816    * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = -1
1817    * StringUtils.lastIndexOf("aabaabaa", "ba", 2) = 2
1818    * </pre>
1819    *
1820    * @param seq the CharSequence to check, may be null
1821    * @param searchSeq the CharSequence to find, may be null
1822    * @param startPos the start position, negative treated as zero
1823    * @return the last index of the search CharSequence (always &le; startPos),
1824    * -1 if no match or {@code null} string input
1825    * @since 2.0
1826    * @since 3.0 Changed signature from lastIndexOf(String, String, int) to lastIndexOf(CharSequence, CharSequence, int)
1827    */
 
1828  30 toggle public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) {
1829  30 if (seq == null || searchSeq == null) {
1830  6 return INDEX_NOT_FOUND;
1831    }
1832  24 return CharSequenceUtils.lastIndexOf(seq, searchSeq, startPos);
1833    }
1834   
1835    /**
1836    * <p>Case in-sensitive find of the last index within a CharSequence.</p>
1837    *
1838    * <p>A {@code null} CharSequence will return {@code -1}.
1839    * A negative start position returns {@code -1}.
1840    * An empty ("") search CharSequence always matches unless the start position is negative.
1841    * A start position greater than the string length searches the whole string.</p>
1842    *
1843    * <pre>
1844    * StringUtils.lastIndexOfIgnoreCase(null, *) = -1
1845    * StringUtils.lastIndexOfIgnoreCase(*, null) = -1
1846    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A") = 7
1847    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B") = 5
1848    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB") = 4
1849    * </pre>
1850    *
1851    * @param str the CharSequence to check, may be null
1852    * @param searchStr the CharSequence to find, may be null
1853    * @return the first index of the search CharSequence,
1854    * -1 if no match or {@code null} string input
1855    * @since 2.5
1856    * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String) to lastIndexOfIgnoreCase(CharSequence, CharSequence)
1857    */
 
1858  14 toggle public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
1859  14 if (str == null || searchStr == null) {
1860  3 return INDEX_NOT_FOUND;
1861    }
1862  11 return lastIndexOfIgnoreCase(str, searchStr, str.length());
1863    }
1864   
1865    /**
1866    * <p>Case in-sensitive find of the last index within a CharSequence
1867    * from the specified position.</p>
1868    *
1869    * <p>A {@code null} CharSequence will return {@code -1}.
1870    * A negative start position returns {@code -1}.
1871    * An empty ("") search CharSequence always matches unless the start position is negative.
1872    * A start position greater than the string length searches the whole string.
1873    * The search starts at the startPos and works backwards; matches starting after the start
1874    * position are ignored.
1875    * </p>
1876    *
1877    * <pre>
1878    * StringUtils.lastIndexOfIgnoreCase(null, *, *) = -1
1879    * StringUtils.lastIndexOfIgnoreCase(*, null, *) = -1
1880    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 8) = 7
1881    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 8) = 5
1882    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "AB", 8) = 4
1883    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 9) = 5
1884    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", -1) = -1
1885    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "A", 0) = 0
1886    * StringUtils.lastIndexOfIgnoreCase("aabaabaa", "B", 0) = -1
1887    * </pre>
1888    *
1889    * @param str the CharSequence to check, may be null
1890    * @param searchStr the CharSequence to find, may be null
1891    * @param startPos the start position
1892    * @return the last index of the search CharSequence (always &le; startPos),
1893    * -1 if no match or {@code null} input
1894    * @since 2.5
1895    * @since 3.0 Changed signature from lastIndexOfIgnoreCase(String, String, int) to lastIndexOfIgnoreCase(CharSequence, CharSequence, int)
1896    */
 
1897  32 toggle public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
1898  32 if (str == null || searchStr == null) {
1899  6 return INDEX_NOT_FOUND;
1900    }
1901  26 if (startPos > str.length() - searchStr.length()) {
1902  15 startPos = str.length() - searchStr.length();
1903    }
1904  26 if (startPos < 0) {
1905  5 return INDEX_NOT_FOUND;
1906    }
1907  21 if (searchStr.length() == 0) {
1908  6 return startPos;
1909    }
1910   
1911  31 for (int i = startPos; i >= 0; i--) {
1912  30 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, searchStr.length())) {
1913  14 return i;
1914    }
1915    }
1916  1 return INDEX_NOT_FOUND;
1917    }
1918   
1919    // Contains
1920    //-----------------------------------------------------------------------
1921    /**
1922    * <p>Checks if CharSequence contains a search character, handling {@code null}.
1923    * This method uses {@link String#indexOf(int)} if possible.</p>
1924    *
1925    * <p>A {@code null} or empty ("") CharSequence will return {@code false}.</p>
1926    *
1927    * <pre>
1928    * StringUtils.contains(null, *) = false
1929    * StringUtils.contains("", *) = false
1930    * StringUtils.contains("abc", 'a') = true
1931    * StringUtils.contains("abc", 'z') = false
1932    * </pre>
1933    *
1934    * @param seq the CharSequence to check, may be null
1935    * @param searchChar the character to find
1936    * @return true if the CharSequence contains the search character,
1937    * false if not or {@code null} string input
1938    * @since 2.0
1939    * @since 3.0 Changed signature from contains(String, int) to contains(CharSequence, int)
1940    */
 
1941  6 toggle public static boolean contains(final CharSequence seq, final int searchChar) {
1942  6 if (isEmpty(seq)) {
1943  2 return false;
1944    }
1945  4 return CharSequenceUtils.indexOf(seq, searchChar, 0) >= 0;
1946    }
1947   
1948    /**
1949    * <p>Checks if CharSequence contains a search CharSequence, handling {@code null}.
1950    * This method uses {@link String#indexOf(String)} if possible.</p>
1951    *
1952    * <p>A {@code null} CharSequence will return {@code false}.</p>
1953    *
1954    * <pre>
1955    * StringUtils.contains(null, *) = false
1956    * StringUtils.contains(*, null) = false
1957    * StringUtils.contains("", "") = true
1958    * StringUtils.contains("abc", "") = true
1959    * StringUtils.contains("abc", "a") = true
1960    * StringUtils.contains("abc", "z") = false
1961    * </pre>
1962    *
1963    * @param seq the CharSequence to check, may be null
1964    * @param searchSeq the CharSequence to find, may be null
1965    * @return true if the CharSequence contains the search CharSequence,
1966    * false if not or {@code null} string input
1967    * @since 2.0
1968    * @since 3.0 Changed signature from contains(String, String) to contains(CharSequence, CharSequence)
1969    */
 
1970  35 toggle public static boolean contains(final CharSequence seq, final CharSequence searchSeq) {
1971  35 if (seq == null || searchSeq == null) {
1972  8 return false;
1973    }
1974  27 return CharSequenceUtils.indexOf(seq, searchSeq, 0) >= 0;
1975    }
1976   
1977    /**
1978    * <p>Checks if CharSequence contains a search CharSequence irrespective of case,
1979    * handling {@code null}. Case-insensitivity is defined as by
1980    * {@link String#equalsIgnoreCase(String)}.
1981    *
1982    * <p>A {@code null} CharSequence will return {@code false}.</p>
1983    *
1984    * <pre>
1985    * StringUtils.containsIgnoreCase(null, *) = false
1986    * StringUtils.containsIgnoreCase(*, null) = false
1987    * StringUtils.containsIgnoreCase("", "") = true
1988    * StringUtils.containsIgnoreCase("abc", "") = true
1989    * StringUtils.containsIgnoreCase("abc", "a") = true
1990    * StringUtils.containsIgnoreCase("abc", "z") = false
1991    * StringUtils.containsIgnoreCase("abc", "A") = true
1992    * StringUtils.containsIgnoreCase("abc", "Z") = false
1993    * </pre>
1994    *
1995    * @param str the CharSequence to check, may be null
1996    * @param searchStr the CharSequence to find, may be null
1997    * @return true if the CharSequence contains the search CharSequence irrespective of
1998    * case or false if not or {@code null} string input
1999    * @since 3.0 Changed signature from containsIgnoreCase(String, String) to containsIgnoreCase(CharSequence, CharSequence)
2000    */
 
2001  40 toggle public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) {
2002  40 if (str == null || searchStr == null) {
2003  7 return false;
2004    }
2005  33 final int len = searchStr.length();
2006  33 final int max = str.length() - len;
2007  35 for (int i = 0; i <= max; i++) {
2008  26 if (CharSequenceUtils.regionMatches(str, true, i, searchStr, 0, len)) {
2009  24 return true;
2010    }
2011    }
2012  9 return false;
2013    }
2014   
2015    /**
2016    * <p>Check whether the given CharSequence contains any whitespace characters.</p>
2017    *
2018    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
2019    *
2020    * @param seq the CharSequence to check (may be {@code null})
2021    * @return {@code true} if the CharSequence is not empty and
2022    * contains at least 1 (breaking) whitespace character
2023    * @since 3.0
2024    */
2025    // From org.springframework.util.StringUtils, under Apache License 2.0
 
2026  7 toggle public static boolean containsWhitespace(final CharSequence seq) {
2027  7 if (isEmpty(seq)) {
2028  1 return false;
2029    }
2030  6 final int strLen = seq.length();
2031  9 for (int i = 0; i < strLen; i++) {
2032  8 if (Character.isWhitespace(seq.charAt(i))) {
2033  5 return true;
2034    }
2035    }
2036  1 return false;
2037    }
2038   
2039    // IndexOfAny chars
2040    //-----------------------------------------------------------------------
2041    /**
2042    * <p>Search a CharSequence to find the first index of any
2043    * character in the given set of characters.</p>
2044    *
2045    * <p>A {@code null} String will return {@code -1}.
2046    * A {@code null} or zero length search array will return {@code -1}.</p>
2047    *
2048    * <pre>
2049    * StringUtils.indexOfAny(null, *) = -1
2050    * StringUtils.indexOfAny("", *) = -1
2051    * StringUtils.indexOfAny(*, null) = -1
2052    * StringUtils.indexOfAny(*, []) = -1
2053    * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
2054    * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
2055    * StringUtils.indexOfAny("aba", ['z']) = -1
2056    * </pre>
2057    *
2058    * @param cs the CharSequence to check, may be null
2059    * @param searchChars the chars to search for, may be null
2060    * @return the index of any of the chars, -1 if no match or null input
2061    * @since 2.0
2062    * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
2063    */
 
2064  22 toggle public static int indexOfAny(final CharSequence cs, final char... searchChars) {
2065  22 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2066  8 return INDEX_NOT_FOUND;
2067    }
2068  14 final int csLen = cs.length();
2069  14 final int csLast = csLen - 1;
2070  14 final int searchLen = searchChars.length;
2071  14 final int searchLast = searchLen - 1;
2072  32 for (int i = 0; i < csLen; i++) {
2073  28 final char ch = cs.charAt(i);
2074  60 for (int j = 0; j < searchLen; j++) {
2075  42 if (searchChars[j] == ch) {
2076  14 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2077    // ch is a supplementary character
2078  10 if (searchChars[j + 1] == cs.charAt(i + 1)) {
2079  6 return i;
2080    }
2081    } else {
2082  4 return i;
2083    }
2084    }
2085    }
2086    }
2087  4 return INDEX_NOT_FOUND;
2088    }
2089   
2090    /**
2091    * <p>Search a CharSequence to find the first index of any
2092    * character in the given set of characters.</p>
2093    *
2094    * <p>A {@code null} String will return {@code -1}.
2095    * A {@code null} search string will return {@code -1}.</p>
2096    *
2097    * <pre>
2098    * StringUtils.indexOfAny(null, *) = -1
2099    * StringUtils.indexOfAny("", *) = -1
2100    * StringUtils.indexOfAny(*, null) = -1
2101    * StringUtils.indexOfAny(*, "") = -1
2102    * StringUtils.indexOfAny("zzabyycdxx", "za") = 0
2103    * StringUtils.indexOfAny("zzabyycdxx", "by") = 3
2104    * StringUtils.indexOfAny("aba","z") = -1
2105    * </pre>
2106    *
2107    * @param cs the CharSequence to check, may be null
2108    * @param searchChars the chars to search for, may be null
2109    * @return the index of any of the chars, -1 if no match or null input
2110    * @since 2.0
2111    * @since 3.0 Changed signature from indexOfAny(String, String) to indexOfAny(CharSequence, String)
2112    */
 
2113  15 toggle public static int indexOfAny(final CharSequence cs, final String searchChars) {
2114  15 if (isEmpty(cs) || isEmpty(searchChars)) {
2115  8 return INDEX_NOT_FOUND;
2116    }
2117  7 return indexOfAny(cs, searchChars.toCharArray());
2118    }
2119   
2120    // ContainsAny
2121    //-----------------------------------------------------------------------
2122    /**
2123    * <p>Checks if the CharSequence contains any character in the given
2124    * set of characters.</p>
2125    *
2126    * <p>A {@code null} CharSequence will return {@code false}.
2127    * A {@code null} or zero length search array will return {@code false}.</p>
2128    *
2129    * <pre>
2130    * StringUtils.containsAny(null, *) = false
2131    * StringUtils.containsAny("", *) = false
2132    * StringUtils.containsAny(*, null) = false
2133    * StringUtils.containsAny(*, []) = false
2134    * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
2135    * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
2136    * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
2137    * StringUtils.containsAny("aba", ['z']) = false
2138    * </pre>
2139    *
2140    * @param cs the CharSequence to check, may be null
2141    * @param searchChars the chars to search for, may be null
2142    * @return the {@code true} if any of the chars are found,
2143    * {@code false} if no match or null input
2144    * @since 2.4
2145    * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
2146    */
 
2147  53 toggle public static boolean containsAny(final CharSequence cs, final char... searchChars) {
2148  53 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2149  13 return false;
2150    }
2151  40 final int csLength = cs.length();
2152  40 final int searchLength = searchChars.length;
2153  40 final int csLast = csLength - 1;
2154  40 final int searchLast = searchLength - 1;
2155  121 for (int i = 0; i < csLength; i++) {
2156  106 final char ch = cs.charAt(i);
2157  342 for (int j = 0; j < searchLength; j++) {
2158  261 if (searchChars[j] == ch) {
2159  33 if (Character.isHighSurrogate(ch)) {
2160  16 if (j == searchLast) {
2161    // missing low surrogate, fine, like String.indexOf(String)
2162  2 return true;
2163    }
2164  14 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2165  6 return true;
2166    }
2167    } else {
2168    // ch is in the Basic Multilingual Plane
2169  17 return true;
2170    }
2171    }
2172    }
2173    }
2174  15 return false;
2175    }
2176   
2177    /**
2178    * <p>
2179    * Checks if the CharSequence contains any character in the given set of characters.
2180    * </p>
2181    *
2182    * <p>
2183    * A {@code null} CharSequence will return {@code false}. A {@code null} search CharSequence will return
2184    * {@code false}.
2185    * </p>
2186    *
2187    * <pre>
2188    * StringUtils.containsAny(null, *) = false
2189    * StringUtils.containsAny("", *) = false
2190    * StringUtils.containsAny(*, null) = false
2191    * StringUtils.containsAny(*, "") = false
2192    * StringUtils.containsAny("zzabyycdxx", "za") = true
2193    * StringUtils.containsAny("zzabyycdxx", "by") = true
2194    * StringUtils.containsAny("zzabyycdxx", "zy") = true
2195    * StringUtils.containsAny("zzabyycdxx", "\tx") = true
2196    * StringUtils.containsAny("zzabyycdxx", "$.#yF") = true
2197    * StringUtils.containsAny("aba","z") = false
2198    * </pre>
2199    *
2200    * @param cs
2201    * the CharSequence to check, may be null
2202    * @param searchChars
2203    * the chars to search for, may be null
2204    * @return the {@code true} if any of the chars are found, {@code false} if no match or null input
2205    * @since 2.4
2206    * @since 3.0 Changed signature from containsAny(String, String) to containsAny(CharSequence, CharSequence)
2207    */
 
2208  21 toggle public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) {
2209  21 if (searchChars == null) {
2210  3 return false;
2211    }
2212  18 return containsAny(cs, CharSequenceUtils.toCharArray(searchChars));
2213    }
2214   
2215    /**
2216    * <p>Checks if the CharSequence contains any of the CharSequences in the given array.</p>
2217    *
2218    * <p>
2219    * A {@code null} {@code cs} CharSequence will return {@code false}. A {@code null} or zero
2220    * length search array will return {@code false}.
2221    * </p>
2222    *
2223    * <pre>
2224    * StringUtils.containsAny(null, *) = false
2225    * StringUtils.containsAny("", *) = false
2226    * StringUtils.containsAny(*, null) = false
2227    * StringUtils.containsAny(*, []) = false
2228    * StringUtils.containsAny("abcd", "ab", null) = true
2229    * StringUtils.containsAny("abcd", "ab", "cd") = true
2230    * StringUtils.containsAny("abc", "d", "abc") = true
2231    * </pre>
2232    *
2233    *
2234    * @param cs The CharSequence to check, may be null
2235    * @param searchCharSequences The array of CharSequences to search for, may be null.
2236    * Individual CharSequences may be null as well.
2237    * @return {@code true} if any of the search CharSequences are found, {@code false} otherwise
2238    * @since 3.4
2239    */
 
2240  16 toggle public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) {
2241  16 if (isEmpty(cs) || ArrayUtils.isEmpty(searchCharSequences)) {
2242  8 return false;
2243    }
2244  8 for (final CharSequence searchCharSequence : searchCharSequences) {
2245  12 if (contains(cs, searchCharSequence)) {
2246  5 return true;
2247    }
2248    }
2249  3 return false;
2250    }
2251   
2252    // IndexOfAnyBut chars
2253    //-----------------------------------------------------------------------
2254    /**
2255    * <p>Searches a CharSequence to find the first index of any
2256    * character not in the given set of characters.</p>
2257    *
2258    * <p>A {@code null} CharSequence will return {@code -1}.
2259    * A {@code null} or zero length search array will return {@code -1}.</p>
2260    *
2261    * <pre>
2262    * StringUtils.indexOfAnyBut(null, *) = -1
2263    * StringUtils.indexOfAnyBut("", *) = -1
2264    * StringUtils.indexOfAnyBut(*, null) = -1
2265    * StringUtils.indexOfAnyBut(*, []) = -1
2266    * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
2267    * StringUtils.indexOfAnyBut("aba", new char[] {'z'} ) = 0
2268    * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} ) = -1
2269   
2270    * </pre>
2271    *
2272    * @param cs the CharSequence to check, may be null
2273    * @param searchChars the chars to search for, may be null
2274    * @return the index of any of the chars, -1 if no match or null input
2275    * @since 2.0
2276    * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
2277    */
 
2278  37 toggle public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
2279  37 if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
2280  8 return INDEX_NOT_FOUND;
2281    }
2282  29 final int csLen = cs.length();
2283  29 final int csLast = csLen - 1;
2284  29 final int searchLen = searchChars.length;
2285  29 final int searchLast = searchLen - 1;
2286  29 outer:
2287  30053 for (int i = 0; i < csLen; i++) {
2288  30038 final char ch = cs.charAt(i);
2289  30065 for (int j = 0; j < searchLen; j++) {
2290  30051 if (searchChars[j] == ch) {
2291  30027 if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
2292  5 if (searchChars[j + 1] == cs.charAt(i + 1)) {
2293  2 continue outer;
2294    }
2295    } else {
2296  30022 continue outer;
2297    }
2298    }
2299    }
2300  14 return i;
2301    }
2302  15 return INDEX_NOT_FOUND;
2303    }
2304   
2305    /**
2306    * <p>Search a CharSequence to find the first index of any
2307    * character not in the given set of characters.</p>
2308    *
2309    * <p>A {@code null} CharSequence will return {@code -1}.
2310    * A {@code null} or empty search string will return {@code -1}.</p>
2311    *
2312    * <pre>
2313    * StringUtils.indexOfAnyBut(null, *) = -1
2314    * StringUtils.indexOfAnyBut("", *) = -1
2315    * StringUtils.indexOfAnyBut(*, null) = -1
2316    * StringUtils.indexOfAnyBut(*, "") = -1
2317    * StringUtils.indexOfAnyBut("zzabyycdxx", "za") = 3
2318    * StringUtils.indexOfAnyBut("zzabyycdxx", "") = -1
2319    * StringUtils.indexOfAnyBut("aba","ab") = -1
2320    * </pre>
2321    *
2322    * @param seq the CharSequence to check, may be null
2323    * @param searchChars the chars to search for, may be null
2324    * @return the index of any of the chars, -1 if no match or null input
2325    * @since 2.0
2326    * @since 3.0 Changed signature from indexOfAnyBut(String, String) to indexOfAnyBut(CharSequence, CharSequence)
2327    */
 
2328  15 toggle public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) {
2329  15 if (isEmpty(seq) || isEmpty(searchChars)) {
2330  8 return INDEX_NOT_FOUND;
2331    }
2332  7 final int strLen = seq.length();
2333  14 for (int i = 0; i < strLen; i++) {
2334  13 final char ch = seq.charAt(i);
2335  13 final boolean chFound = CharSequenceUtils.indexOf(searchChars, ch, 0) >= 0;
2336  13 if (i + 1 < strLen && Character.isHighSurrogate(ch)) {
2337  5 final char ch2 = seq.charAt(i + 1);
2338  5 if (chFound && CharSequenceUtils.indexOf(searchChars, ch2, 0) < 0) {
2339  3 return i;
2340    }
2341    } else {
2342  8 if (!chFound) {
2343  3 return i;
2344    }
2345    }
2346    }
2347  1 return INDEX_NOT_FOUND;
2348    }
2349   
2350    // ContainsOnly
2351    //-----------------------------------------------------------------------
2352    /**
2353    * <p>Checks if the CharSequence contains only certain characters.</p>
2354    *
2355    * <p>A {@code null} CharSequence will return {@code false}.
2356    * A {@code null} valid character array will return {@code false}.
2357    * An empty CharSequence (length()=0) always returns {@code true}.</p>
2358    *
2359    * <pre>
2360    * StringUtils.containsOnly(null, *) = false
2361    * StringUtils.containsOnly(*, null) = false
2362    * StringUtils.containsOnly("", *) = true
2363    * StringUtils.containsOnly("ab", '') = false
2364    * StringUtils.containsOnly("abab", 'abc') = true
2365    * StringUtils.containsOnly("ab1", 'abc') = false
2366    * StringUtils.containsOnly("abz", 'abc') = false
2367    * </pre>
2368    *
2369    * @param cs the String to check, may be null
2370    * @param valid an array of valid chars, may be null
2371    * @return true if it only contains valid chars and is non-null
2372    * @since 3.0 Changed signature from containsOnly(String, char[]) to containsOnly(CharSequence, char...)
2373    */
 
2374  30 toggle public static boolean containsOnly(final CharSequence cs, final char... valid) {
2375    // All these pre-checks are to maintain API with an older version
2376  30 if (valid == null || cs == null) {
2377  3 return false;
2378    }
2379  27 if (cs.length() == 0) {
2380  4 return true;
2381    }
2382  23 if (valid.length == 0) {
2383  2 return false;
2384    }
2385  21 return indexOfAnyBut(cs, valid) == INDEX_NOT_FOUND;
2386    }
2387   
2388    /**
2389    * <p>Checks if the CharSequence contains only certain characters.</p>
2390    *
2391    * <p>A {@code null} CharSequence will return {@code false}.
2392    * A {@code null} valid character String will return {@code false}.
2393    * An empty String (length()=0) always returns {@code true}.</p>
2394    *
2395    * <pre>
2396    * StringUtils.containsOnly(null, *) = false
2397    * StringUtils.containsOnly(*, null) = false
2398    * StringUtils.containsOnly("", *) = true
2399    * StringUtils.containsOnly("ab", "") = false
2400    * StringUtils.containsOnly("abab", "abc") = true
2401    * StringUtils.containsOnly("ab1", "abc") = false
2402    * StringUtils.containsOnly("abz", "abc") = false
2403    * </pre>
2404    *
2405    * @param cs the CharSequence to check, may be null
2406    * @param validChars a String of valid chars, may be null
2407    * @return true if it only contains valid chars and is non-null
2408    * @since 2.0
2409    * @since 3.0 Changed signature from containsOnly(String, String) to containsOnly(CharSequence, String)
2410    */
 
2411  15 toggle public static boolean containsOnly(final CharSequence cs, final String validChars) {
2412  15 if (cs == null || validChars == null) {
2413  3 return false;
2414    }
2415  12 return containsOnly(cs, validChars.toCharArray());
2416    }
2417   
2418    // ContainsNone
2419    //-----------------------------------------------------------------------
2420    /**
2421    * <p>Checks that the CharSequence does not contain certain characters.</p>
2422    *
2423    * <p>A {@code null} CharSequence will return {@code true}.
2424    * A {@code null} invalid character array will return {@code true}.
2425    * An empty CharSequence (length()=0) always returns true.</p>
2426    *
2427    * <pre>
2428    * StringUtils.containsNone(null, *) = true
2429    * StringUtils.containsNone(*, null) = true
2430    * StringUtils.containsNone("", *) = true
2431    * StringUtils.containsNone("ab", '') = true
2432    * StringUtils.containsNone("abab", 'xyz') = true
2433    * StringUtils.containsNone("ab1", 'xyz') = true
2434    * StringUtils.containsNone("abz", 'xyz') = false
2435    * </pre>
2436    *
2437    * @param cs the CharSequence to check, may be null
2438    * @param searchChars an array of invalid chars, may be null
2439    * @return true if it contains none of the invalid chars, or is null
2440    * @since 2.0
2441    * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
2442    */
 
2443  61 toggle public static boolean containsNone(final CharSequence cs, final char... searchChars) {
2444  61 if (cs == null || searchChars == null) {
2445  3 return true;
2446    }
2447  58 final int csLen = cs.length();
2448  58 final int csLast = csLen - 1;
2449  58 final int searchLen = searchChars.length;
2450  58 final int searchLast = searchLen - 1;
2451  164 for (int i = 0; i < csLen; i++) {
2452  128 final char ch = cs.charAt(i);
2453  456 for (int j = 0; j < searchLen; j++) {
2454  350 if (searchChars[j] == ch) {
2455  30 if (Character.isHighSurrogate(ch)) {
2456  16 if (j == searchLast) {
2457    // missing low surrogate, fine, like String.indexOf(String)
2458  2 return false;
2459    }
2460  14 if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
2461  6 return false;
2462    }
2463    } else {
2464    // ch is in the Basic Multilingual Plane
2465  14 return false;
2466    }
2467    }
2468    }
2469    }
2470  36 return true;
2471    }
2472   
2473    /**
2474    * <p>Checks that the CharSequence does not contain certain characters.</p>
2475    *
2476    * <p>A {@code null} CharSequence will return {@code true}.
2477    * A {@code null} invalid character array will return {@code true}.
2478    * An empty String ("") always returns true.</p>
2479    *
2480    * <pre>
2481    * StringUtils.containsNone(null, *) = true
2482    * StringUtils.containsNone(*, null) = true
2483    * StringUtils.containsNone("", *) = true
2484    * StringUtils.containsNone("ab", "") = true
2485    * StringUtils.containsNone("abab", "xyz") = true
2486    * StringUtils.containsNone("ab1", "xyz") = true
2487    * StringUtils.containsNone("abz", "xyz") = false
2488    * </pre>
2489    *
2490    * @param cs the CharSequence to check, may be null
2491    * @param invalidChars a String of invalid chars, may be null
2492    * @return true if it contains none of the invalid chars, or is null
2493    * @since 2.0
2494    * @since 3.0 Changed signature from containsNone(String, String) to containsNone(CharSequence, String)
2495    */
 
2496  24 toggle public static boolean containsNone(final CharSequence cs, final String invalidChars) {
2497  24 if (cs == null || invalidChars == null) {
2498  3 return true;
2499    }
2500  21 return containsNone(cs, invalidChars.toCharArray());
2501    }
2502   
2503    // IndexOfAny strings
2504    //-----------------------------------------------------------------------
2505    /**
2506    * <p>Find the first index of any of a set of potential substrings.</p>
2507    *
2508    * <p>A {@code null} CharSequence will return {@code -1}.
2509    * A {@code null} or zero length search array will return {@code -1}.
2510    * A {@code null} search array entry will be ignored, but a search
2511    * array containing "" will return {@code 0} if {@code str} is not
2512    * null. This method uses {@link String#indexOf(String)} if possible.</p>
2513    *
2514    * <pre>
2515    * StringUtils.indexOfAny(null, *) = -1
2516    * StringUtils.indexOfAny(*, null) = -1
2517    * StringUtils.indexOfAny(*, []) = -1
2518    * StringUtils.indexOfAny("zzabyycdxx", ["ab","cd"]) = 2
2519    * StringUtils.indexOfAny("zzabyycdxx", ["cd","ab"]) = 2
2520    * StringUtils.indexOfAny("zzabyycdxx", ["mn","op"]) = -1
2521    * StringUtils.indexOfAny("zzabyycdxx", ["zab","aby"]) = 1
2522    * StringUtils.indexOfAny("zzabyycdxx", [""]) = 0
2523    * StringUtils.indexOfAny("", [""]) = 0
2524    * StringUtils.indexOfAny("", ["a"]) = -1
2525    * </pre>
2526    *
2527    * @param str the CharSequence to check, may be null
2528    * @param searchStrs the CharSequences to search for, may be null
2529    * @return the first index of any of the searchStrs in str, -1 if no match
2530    * @since 3.0 Changed signature from indexOfAny(String, String[]) to indexOfAny(CharSequence, CharSequence...)
2531    */
 
2532  14 toggle public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2533  14 if (str == null || searchStrs == null) {
2534  5 return INDEX_NOT_FOUND;
2535    }
2536   
2537    // String's can't have a MAX_VALUEth index.
2538  9 int ret = Integer.MAX_VALUE;
2539   
2540  9 int tmp = 0;
2541  9 for (final CharSequence search : searchStrs) {
2542  8 if (search == null) {
2543  2 continue;
2544    }
2545  6 tmp = CharSequenceUtils.indexOf(str, search, 0);
2546  6 if (tmp == INDEX_NOT_FOUND) {
2547  2 continue;
2548    }
2549   
2550  4 if (tmp < ret) {
2551  3 ret = tmp;
2552    }
2553    }
2554   
2555  9 return ret == Integer.MAX_VALUE ? INDEX_NOT_FOUND : ret;
2556    }
2557   
2558    /**
2559    * <p>Find the latest index of any of a set of potential substrings.</p>
2560    *
2561    * <p>A {@code null} CharSequence will return {@code -1}.
2562    * A {@code null} search array will return {@code -1}.
2563    * A {@code null} or zero length search array entry will be ignored,
2564    * but a search array containing "" will return the length of {@code str}
2565    * if {@code str} is not null. This method uses {@link String#indexOf(String)} if possible</p>
2566    *
2567    * <pre>
2568    * StringUtils.lastIndexOfAny(null, *) = -1
2569    * StringUtils.lastIndexOfAny(*, null) = -1
2570    * StringUtils.lastIndexOfAny(*, []) = -1
2571    * StringUtils.lastIndexOfAny(*, [null]) = -1
2572    * StringUtils.lastIndexOfAny("zzabyycdxx", ["ab","cd"]) = 6
2573    * StringUtils.lastIndexOfAny("zzabyycdxx", ["cd","ab"]) = 6
2574    * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2575    * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn","op"]) = -1
2576    * StringUtils.lastIndexOfAny("zzabyycdxx", ["mn",""]) = 10
2577    * </pre>
2578    *
2579    * @param str the CharSequence to check, may be null
2580    * @param searchStrs the CharSequences to search for, may be null
2581    * @return the last index of any of the CharSequences, -1 if no match
2582    * @since 3.0 Changed signature from lastIndexOfAny(String, String[]) to lastIndexOfAny(CharSequence, CharSequence)
2583    */
 
2584  18 toggle public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) {
2585  18 if (str == null || searchStrs == null) {
2586  7 return INDEX_NOT_FOUND;
2587    }
2588  11 int ret = INDEX_NOT_FOUND;
2589  11 int tmp = 0;
2590  11 for (final CharSequence search : searchStrs) {
2591  9 if (search == null) {
2592  3 continue;
2593    }
2594  6 tmp = CharSequenceUtils.lastIndexOf(str, search, str.length());
2595  6 if (tmp > ret) {
2596  4 ret = tmp;
2597    }
2598    }
2599  11 return ret;
2600    }
2601   
2602    // Substring
2603    //-----------------------------------------------------------------------
2604    /**
2605    * <p>Gets a substring from the specified String avoiding exceptions.</p>
2606    *
2607    * <p>A negative start position can be used to start {@code n}
2608    * characters from the end of the String.</p>
2609    *
2610    * <p>A {@code null} String will return {@code null}.
2611    * An empty ("") String will return "".</p>
2612    *
2613    * <pre>
2614    * StringUtils.substring(null, *) = null
2615    * StringUtils.substring("", *) = ""
2616    * StringUtils.substring("abc", 0) = "abc"
2617    * StringUtils.substring("abc", 2) = "c"
2618    * StringUtils.substring("abc", 4) = ""
2619    * StringUtils.substring("abc", -2) = "bc"
2620    * StringUtils.substring("abc", -4) = "abc"
2621    * </pre>
2622    *
2623    * @param str the String to get the substring from, may be null
2624    * @param start the position to start from, negative means
2625    * count back from the end of the String by this many characters
2626    * @return substring from start position, {@code null} if null String input
2627    */
 
2628  22 toggle public static String substring(final String str, int start) {
2629  22 if (str == null) {
2630  1 return null;
2631    }
2632   
2633    // handle negatives, which means last n characters
2634  21 if (start < 0) {
2635  8 start = str.length() + start; // remember start is negative
2636    }
2637   
2638  21 if (start < 0) {
2639  1 start = 0;
2640    }
2641  21 if (start > str.length()) {
2642  3 return EMPTY;
2643    }
2644   
2645  18 return str.substring(start);
2646    }
2647   
2648    /**
2649    * <p>Gets a substring from the specified String avoiding exceptions.</p>
2650    *
2651    * <p>A negative start position can be used to start/end {@code n}
2652    * characters from the end of the String.</p>
2653    *
2654    * <p>The returned substring starts with the character in the {@code start}
2655    * position and ends before the {@code end} position. All position counting is
2656    * zero-based -- i.e., to start at the beginning of the string use
2657    * {@code start = 0}. Negative start and end positions can be used to
2658    * specify offsets relative to the end of the String.</p>
2659    *
2660    * <p>If {@code start} is not strictly to the left of {@code end}, ""
2661    * is returned.</p>
2662    *
2663    * <pre>
2664    * StringUtils.substring(null, *, *) = null
2665    * StringUtils.substring("", * , *) = "";
2666    * StringUtils.substring("abc", 0, 2) = "ab"
2667    * StringUtils.substring("abc", 2, 0) = ""
2668    * StringUtils.substring("abc", 2, 4) = "c"
2669    * StringUtils.substring("abc", 4, 6) = ""
2670    * StringUtils.substring("abc", 2, 2) = ""
2671    * StringUtils.substring("abc", -2, -1) = "b"
2672    * StringUtils.substring("abc", -4, 2) = "ab"
2673    * </pre>
2674    *
2675    * @param str the String to get the substring from, may be null
2676    * @param start the position to start from, negative means
2677    * count back from the end of the String by this many characters
2678    * @param end the position to end at (exclusive), negative means
2679    * count back from the end of the String by this many characters
2680    * @return substring from start position to end position,
2681    * {@code null} if null String input
2682    */
 
2683  19 toggle public static String substring(final String str, int start, int end) {
2684  19 if (str == null) {
2685  2 return null;
2686    }
2687   
2688    // handle negatives
2689  17 if (end < 0) {
2690  7 end = str.length() + end; // remember end is negative
2691    }
2692  17 if (start < 0) {
2693  4 start = str.length() + start; // remember start is negative
2694    }
2695   
2696    // check length next
2697  17 if (end > str.length()) {
2698  2 end = str.length();
2699    }
2700   
2701    // if start is greater than end, return ""
2702  17 if (start > end) {
2703  2 return EMPTY;
2704    }
2705   
2706  15 if (start < 0) {
2707  1 start = 0;
2708    }
2709  15 if (end < 0) {
2710  1 end = 0;
2711    }
2712   
2713  15 return str.substring(start, end);
2714    }
2715   
2716    // Left/Right/Mid
2717    //-----------------------------------------------------------------------
2718    /**
2719    * <p>Gets the leftmost {@code len} characters of a String.</p>
2720    *
2721    * <p>If {@code len} characters are not available, or the
2722    * String is {@code null}, the String will be returned without
2723    * an exception. An empty String is returned if len is negative.</p>
2724    *
2725    * <pre>
2726    * StringUtils.left(null, *) = null
2727    * StringUtils.left(*, -ve) = ""
2728    * StringUtils.left("", *) = ""
2729    * StringUtils.left("abc", 0) = ""
2730    * StringUtils.left("abc", 2) = "ab"
2731    * StringUtils.left("abc", 4) = "abc"
2732    * </pre>
2733    *
2734    * @param str the String to get the leftmost characters from, may be null
2735    * @param len the length of the required String
2736    * @return the leftmost characters, {@code null} if null String input
2737    */
 
2738  10 toggle public static String left(final String str, final int len) {
2739  10 if (str == null) {
2740  3 return null;
2741    }
2742  7 if (len < 0) {
2743  2 return EMPTY;
2744    }
2745  5 if (str.length() <= len) {
2746  3 return str;
2747    }
2748  2 return str.substring(0, len);
2749    }
2750   
2751    /**
2752    * <p>Gets the rightmost {@code len} characters of a String.</p>
2753    *
2754    * <p>If {@code len} characters are not available, or the String
2755    * is {@code null}, the String will be returned without an
2756    * an exception. An empty String is returned if len is negative.</p>
2757    *
2758    * <pre>
2759    * StringUtils.right(null, *) = null
2760    * StringUtils.right(*, -ve) = ""
2761    * StringUtils.right("", *) = ""
2762    * StringUtils.right("abc", 0) = ""
2763    * StringUtils.right("abc", 2) = "bc"
2764    * StringUtils.right("abc", 4) = "abc"
2765    * </pre>
2766    *
2767    * @param str the String to get the rightmost characters from, may be null
2768    * @param len the length of the required String
2769    * @return the rightmost characters, {@code null} if null String input
2770    */
 
2771  10 toggle public static String right(final String str, final int len) {
2772  10 if (str == null) {
2773  3 return null;
2774    }
2775  7 if (len < 0) {
2776  2 return EMPTY;
2777    }
2778  5 if (str.length() <= len) {
2779  3 return str;
2780    }
2781  2 return str.substring(str.length() - len);
2782    }
2783   
2784    /**
2785    * <p>Gets {@code len} characters from the middle of a String.</p>
2786    *
2787    * <p>If {@code len} characters are not available, the remainder
2788    * of the String will be returned without an exception. If the
2789    * String is {@code null}, {@code null} will be returned.
2790    * An empty String is returned if len is negative or exceeds the
2791    * length of {@code str}.</p>
2792    *
2793    * <pre>
2794    * StringUtils.mid(null, *, *) = null
2795    * StringUtils.mid(*, *, -ve) = ""
2796    * StringUtils.mid("", 0, *) = ""
2797    * StringUtils.mid("abc", 0, 2) = "ab"
2798    * StringUtils.mid("abc", 0, 4) = "abc"
2799    * StringUtils.mid("abc", 2, 4) = "c"
2800    * StringUtils.mid("abc", 4, 2) = ""
2801    * StringUtils.mid("abc", -2, 2) = "ab"
2802    * </pre>
2803    *
2804    * @param str the String to get the characters from, may be null
2805    * @param pos the position to start from, negative treated as zero
2806    * @param len the length of the required String
2807    * @return the middle characters, {@code null} if null String input
2808    */
 
2809  16 toggle public static String mid(final String str, int pos, final int len) {
2810  16 if (str == null) {
2811  4 return null;
2812    }
2813  12 if (len < 0 || pos > str.length()) {
2814  3 return EMPTY;
2815    }
2816  9 if (pos < 0) {
2817  1 pos = 0;
2818    }
2819  9 if (str.length() <= pos + len) {
2820  5 return str.substring(pos);
2821    }
2822  4 return str.substring(pos, pos + len);
2823    }
2824   
2825    // SubStringAfter/SubStringBefore
2826    //-----------------------------------------------------------------------
2827    /**
2828    * <p>Gets the substring before the first occurrence of a separator.
2829    * The separator is not returned.</p>
2830    *
2831    * <p>A {@code null} string input will return {@code null}.
2832    * An empty ("") string input will return the empty string.
2833    * A {@code null} separator will return the input string.</p>
2834    *
2835    * <p>If nothing is found, the string input is returned.</p>
2836    *
2837    * <pre>
2838    * StringUtils.substringBefore(null, *) = null
2839    * StringUtils.substringBefore("", *) = ""
2840    * StringUtils.substringBefore("abc", "a") = ""
2841    * StringUtils.substringBefore("abcba", "b") = "a"
2842    * StringUtils.substringBefore("abc", "c") = "ab"
2843    * StringUtils.substringBefore("abc", "d") = "abc"
2844    * StringUtils.substringBefore("abc", "") = ""
2845    * StringUtils.substringBefore("abc", null) = "abc"
2846    * </pre>
2847    *
2848    * @param str the String to get a substring from, may be null
2849    * @param separator the String to search for, may be null
2850    * @return the substring before the first occurrence of the separator,
2851    * {@code null} if null String input
2852    * @since 2.0
2853    */
 
2854  14 toggle public static String substringBefore(final String str, final String separator) {
2855  14 if (isEmpty(str) || separator == null) {
2856  7 return str;
2857    }
2858  7 if (separator.isEmpty()) {
2859  1 return EMPTY;
2860    }
2861  6 final int pos = str.indexOf(separator);
2862  6 if (pos == INDEX_NOT_FOUND) {
2863  1 return str;
2864    }
2865  5 return str.substring(0, pos);
2866    }
2867   
2868    /**
2869    * <p>Gets the substring after the first occurrence of a separator.
2870    * The separator is not returned.</p>
2871    *
2872    * <p>A {@code null} string input will return {@code null}.
2873    * An empty ("") string input will return the empty string.
2874    * A {@code null} separator will return the empty string if the
2875    * input string is not {@code null}.</p>
2876    *
2877    * <p>If nothing is found, the empty string is returned.</p>
2878    *
2879    * <pre>
2880    * StringUtils.substringAfter(null, *) = null
2881    * StringUtils.substringAfter("", *) = ""
2882    * StringUtils.substringAfter(*, null) = ""
2883    * StringUtils.substringAfter("abc", "a") = "bc"
2884    * StringUtils.substringAfter("abcba", "b") = "cba"
2885    * StringUtils.substringAfter("abc", "c") = ""
2886    * StringUtils.substringAfter("abc", "d") = ""
2887    * StringUtils.substringAfter("abc", "") = "abc"
2888    * </pre>
2889    *
2890    * @param str the String to get a substring from, may be null
2891    * @param separator the String to search for, may be null
2892    * @return the substring after the first occurrence of the separator,
2893    * {@code null} if null String input
2894    * @since 2.0
2895    */
 
2896  14 toggle public static String substringAfter(final String str, final String separator) {
2897  14 if (isEmpty(str)) {
2898  6 return str;
2899    }
2900  8 if (separator == null) {
2901  1 return EMPTY;
2902    }
2903  7 final int pos = str.indexOf(separator);
2904  7 if (pos == INDEX_NOT_FOUND) {
2905  1 return EMPTY;
2906    }
2907  6 return str.substring(pos + separator.length());
2908    }
2909   
2910    /**
2911    * <p>Gets the substring before the last occurrence of a separator.
2912    * The separator is not returned.</p>
2913    *
2914    * <p>A {@code null} string input will return {@code null}.
2915    * An empty ("") string input will return the empty string.
2916    * An empty or {@code null} separator will return the input string.</p>
2917    *
2918    * <p>If nothing is found, the string input is returned.</p>
2919    *
2920    * <pre>
2921    * StringUtils.substringBeforeLast(null, *) = null
2922    * StringUtils.substringBeforeLast("", *) = ""
2923    * StringUtils.substringBeforeLast("abcba", "b") = "abc"
2924    * StringUtils.substringBeforeLast("abc", "c") = "ab"
2925    * StringUtils.substringBeforeLast("a", "a") = ""
2926    * StringUtils.substringBeforeLast("a", "z") = "a"
2927    * StringUtils.substringBeforeLast("a", null) = "a"
2928    * StringUtils.substringBeforeLast("a", "") = "a"
2929    * </pre>
2930    *
2931    * @param str the String to get a substring from, may be null
2932    * @param separator the String to search for, may be null
2933    * @return the substring before the last occurrence of the separator,
2934    * {@code null} if null String input
2935    * @since 2.0
2936    */
 
2937  18 toggle public static String substringBeforeLast(final String str, final String separator) {
2938  18 if (isEmpty(str) || isEmpty(separator)) {
2939  9 return str;
2940    }
2941  9 final int pos = str.lastIndexOf(separator);
2942  9 if (pos == INDEX_NOT_FOUND) {
2943  2 return str;
2944    }
2945  7 return str.substring(0, pos);
2946    }
2947   
2948    /**
2949    * <p>Gets the substring after the last occurrence of a separator.
2950    * The separator is not returned.</p>
2951    *
2952    * <p>A {@code null} string input will return {@code null}.
2953    * An empty ("") string input will return the empty string.
2954    * An empty or {@code null} separator will return the empty string if
2955    * the input string is not {@code null}.</p>
2956    *
2957    * <p>If nothing is found, the empty string is returned.</p>
2958    *
2959    * <pre>
2960    * StringUtils.substringAfterLast(null, *) = null
2961    * StringUtils.substringAfterLast("", *) = ""
2962    * StringUtils.substringAfterLast(*, "") = ""
2963    * StringUtils.substringAfterLast(*, null) = ""
2964    * StringUtils.substringAfterLast("abc", "a") = "bc"
2965    * StringUtils.substringAfterLast("abcba", "b") = "a"
2966    * StringUtils.substringAfterLast("abc", "c") = ""
2967    * StringUtils.substringAfterLast("a", "a") = ""
2968    * StringUtils.substringAfterLast("a", "z") = ""
2969    * </pre>
2970    *
2971    * @param str the String to get a substring from, may be null
2972    * @param separator the String to search for, may be null
2973    * @return the substring after the last occurrence of the separator,
2974    * {@code null} if null String input
2975    * @since 2.0
2976    */
 
2977  15 toggle public static String substringAfterLast(final String str, final String separator) {
2978  15 if (isEmpty(str)) {
2979  7 return str;
2980    }
2981  8 if (isEmpty(separator)) {
2982  2 return EMPTY;
2983    }
2984  6 final int pos = str.lastIndexOf(separator);
2985  6 if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) {
2986  2 return EMPTY;
2987    }
2988  4 return str.substring(pos + separator.length());
2989    }
2990   
2991    // Substring between
2992    //-----------------------------------------------------------------------
2993    /**
2994    * <p>Gets the String that is nested in between two instances of the
2995    * same String.</p>
2996    *
2997    * <p>A {@code null} input String returns {@code null}.
2998    * A {@code null} tag returns {@code null}.</p>
2999    *
3000    * <pre>
3001    * StringUtils.substringBetween(null, *) = null
3002    * StringUtils.substringBetween("", "") = ""
3003    * StringUtils.substringBetween("", "tag") = null
3004    * StringUtils.substringBetween("tagabctag", null) = null
3005    * StringUtils.substringBetween("tagabctag", "") = ""
3006    * StringUtils.substringBetween("tagabctag", "tag") = "abc"
3007    * </pre>
3008    *
3009    * @param str the String containing the substring, may be null
3010    * @param tag the String before and after the substring, may be null
3011    * @return the substring, {@code null} if no match
3012    * @since 2.0
3013    */
 
3014  10 toggle public static String substringBetween(final String str, final String tag) {
3015  10 return substringBetween(str, tag, tag);
3016    }
3017   
3018    /**
3019    * <p>Gets the String that is nested in between two Strings.
3020    * Only the first match is returned.</p>
3021    *
3022    * <p>A {@code null} input String returns {@code null}.
3023    * A {@code null} open/close returns {@code null} (no match).
3024    * An empty ("") open and close returns an empty string.</p>
3025    *
3026    * <pre>
3027    * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
3028    * StringUtils.substringBetween(null, *, *) = null
3029    * StringUtils.substringBetween(*, null, *) = null
3030    * StringUtils.substringBetween(*, *, null) = null
3031    * StringUtils.substringBetween("", "", "") = ""
3032    * StringUtils.substringBetween("", "", "]") = null
3033    * StringUtils.substringBetween("", "[", "]") = null
3034    * StringUtils.substringBetween("yabcz", "", "") = ""
3035    * StringUtils.substringBetween("yabcz", "y", "z") = "abc"
3036    * StringUtils.substringBetween("yabczyabcz", "y", "z") = "abc"
3037    * </pre>
3038    *
3039    * @param str the String containing the substring, may be null
3040    * @param open the String before the substring, may be null
3041    * @param close the String after the substring, may be null
3042    * @return the substring, {@code null} if no match
3043    * @since 2.0
3044    */
 
3045  19 toggle public static String substringBetween(final String str, final String open, final String close) {
3046  19 if (str == null || open == null || close == null) {
3047  5 return null;
3048    }
3049  14 final int start = str.indexOf(open);
3050  14 if (start != INDEX_NOT_FOUND) {
3051  12 final int end = str.indexOf(close, start + open.length());
3052  12 if (end != INDEX_NOT_FOUND) {
3053  10 return str.substring(start + open.length(), end);
3054    }
3055    }
3056  4 return null;
3057    }
3058   
3059    /**
3060    * <p>Searches a String for substrings delimited by a start and end tag,
3061    * returning all matching substrings in an array.</p>
3062    *
3063    * <p>A {@code null} input String returns {@code null}.
3064    * A {@code null} open/close returns {@code null} (no match).
3065    * An empty ("") open/close returns {@code null} (no match).</p>
3066    *
3067    * <pre>
3068    * StringUtils.substringsBetween("[a][b][c]", "[", "]") = ["a","b","c"]
3069    * StringUtils.substringsBetween(null, *, *) = null
3070    * StringUtils.substringsBetween(*, null, *) = null
3071    * StringUtils.substringsBetween(*, *, null) = null
3072    * StringUtils.substringsBetween("", "[", "]") = []
3073    * </pre>
3074    *
3075    * @param str the String containing the substrings, null returns null, empty returns empty
3076    * @param open the String identifying the start of the substring, empty returns null
3077    * @param close the String identifying the end of the substring, empty returns null
3078    * @return a String Array of substrings, or {@code null} if no match
3079    * @since 2.3
3080    */
 
3081  14 toggle public static String[] substringsBetween(final String str, final String open, final String close) {
3082  14 if (str == null || isEmpty(open) || isEmpty(close)) {
3083  4 return null;
3084    }
3085  10 final int strLen = str.length();
3086  10 if (strLen == 0) {
3087  1 return ArrayUtils.EMPTY_STRING_ARRAY;
3088    }
3089  9 final int closeLen = close.length();
3090  9 final int openLen = open.length();
3091  9 final List<String> list = new ArrayList<>();
3092  9 int pos = 0;
3093  19 while (pos < strLen - closeLen) {
3094  17 int start = str.indexOf(open, pos);
3095  17 if (start < 0) {
3096  6 break;
3097    }
3098  11 start += openLen;
3099  11 final int end = str.indexOf(close, start);
3100  11 if (end < 0) {
3101  1 break;
3102    }
3103  10 list.add(str.substring(start, end));
3104  10 pos = end + closeLen;
3105    }
3106  9 if (list.isEmpty()) {
3107  3 return null;
3108    }
3109  6 return list.toArray(new String [list.size()]);
3110    }
3111   
3112    // Nested extraction
3113    //-----------------------------------------------------------------------
3114   
3115    // Splitting
3116    //-----------------------------------------------------------------------
3117    /**
3118    * <p>Splits the provided text into an array, using whitespace as the
3119    * separator.
3120    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3121    *
3122    * <p>The separator is not included in the returned String array.
3123    * Adjacent separators are treated as one separator.
3124    * For more control over the split use the StrTokenizer class.</p>
3125    *
3126    * <p>A {@code null} input String returns {@code null}.</p>
3127    *
3128    * <pre>
3129    * StringUtils.split(null) = null
3130    * StringUtils.split("") = []
3131    * StringUtils.split("abc def") = ["abc", "def"]
3132    * StringUtils.split("abc def") = ["abc", "def"]
3133    * StringUtils.split(" abc ") = ["abc"]
3134    * </pre>
3135    *
3136    * @param str the String to parse, may be null
3137    * @return an array of parsed Strings, {@code null} if null String input
3138    */
 
3139  5 toggle public static String[] split(final String str) {
3140  5 return split(str, null, -1);
3141    }
3142   
3143    /**
3144    * <p>Splits the provided text into an array, separator specified.
3145    * This is an alternative to using StringTokenizer.</p>
3146    *
3147    * <p>The separator is not included in the returned String array.
3148    * Adjacent separators are treated as one separator.
3149    * For more control over the split use the StrTokenizer class.</p>
3150    *
3151    * <p>A {@code null} input String returns {@code null}.</p>
3152    *
3153    * <pre>
3154    * StringUtils.split(null, *) = null
3155    * StringUtils.split("", *) = []
3156    * StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
3157    * StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
3158    * StringUtils.split("a:b:c", '.') = ["a:b:c"]
3159    * StringUtils.split("a b c", ' ') = ["a", "b", "c"]
3160    * </pre>
3161    *
3162    * @param str the String to parse, may be null
3163    * @param separatorChar the character used as the delimiter
3164    * @return an array of parsed Strings, {@code null} if null String input
3165    * @since 2.0
3166    */
 
3167  9 toggle public static String[] split(final String str, final char separatorChar) {
3168  9 return splitWorker(str, separatorChar, false);
3169    }
3170   
3171    /**
3172    * <p>Splits the provided text into an array, separators specified.
3173    * This is an alternative to using StringTokenizer.</p>
3174    *
3175    * <p>The separator is not included in the returned String array.
3176    * Adjacent separators are treated as one separator.
3177    * For more control over the split use the StrTokenizer class.</p>
3178    *
3179    * <p>A {@code null} input String returns {@code null}.
3180    * A {@code null} separatorChars splits on whitespace.</p>
3181    *
3182    * <pre>
3183    * StringUtils.split(null, *) = null
3184    * StringUtils.split("", *) = []
3185    * StringUtils.split("abc def", null) = ["abc", "def"]
3186    * StringUtils.split("abc def", " ") = ["abc", "def"]
3187    * StringUtils.split("abc def", " ") = ["abc", "def"]
3188    * StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3189    * </pre>
3190    *
3191    * @param str the String to parse, may be null
3192    * @param separatorChars the characters used as the delimiters,
3193    * {@code null} splits on whitespace
3194    * @return an array of parsed Strings, {@code null} if null String input
3195    */
 
3196  3128 toggle public static String[] split(final String str, final String separatorChars) {
3197  3128 return splitWorker(str, separatorChars, -1, false);
3198    }
3199   
3200    /**
3201    * <p>Splits the provided text into an array with a maximum length,
3202    * separators specified.</p>
3203    *
3204    * <p>The separator is not included in the returned String array.
3205    * Adjacent separators are treated as one separator.</p>
3206    *
3207    * <p>A {@code null} input String returns {@code null}.
3208    * A {@code null} separatorChars splits on whitespace.</p>
3209    *
3210    * <p>If more than {@code max} delimited substrings are found, the last
3211    * returned string includes all characters after the first {@code max - 1}
3212    * returned strings (including separator characters).</p>
3213    *
3214    * <pre>
3215    * StringUtils.split(null, *, *) = null
3216    * StringUtils.split("", *, *) = []
3217    * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"]
3218    * StringUtils.split("ab cd ef", null, 0) = ["ab", "cd", "ef"]
3219    * StringUtils.split("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
3220    * StringUtils.split("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
3221    * </pre>
3222    *
3223    * @param str the String to parse, may be null
3224    * @param separatorChars the characters used as the delimiters,
3225    * {@code null} splits on whitespace
3226    * @param max the maximum number of elements to include in the
3227    * array. A zero or negative value implies no limit
3228    * @return an array of parsed Strings, {@code null} if null String input
3229    */
 
3230  6261 toggle public static String[] split(final String str, final String separatorChars, final int max) {
3231  6261 return splitWorker(str, separatorChars, max, false);
3232    }
3233   
3234    /**
3235    * <p>Splits the provided text into an array, separator string specified.</p>
3236    *
3237    * <p>The separator(s) will not be included in the returned String array.
3238    * Adjacent separators are treated as one separator.</p>
3239    *
3240    * <p>A {@code null} input String returns {@code null}.
3241    * A {@code null} separator splits on whitespace.</p>
3242    *
3243    * <pre>
3244    * StringUtils.splitByWholeSeparator(null, *) = null
3245    * StringUtils.splitByWholeSeparator("", *) = []
3246    * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
3247    * StringUtils.splitByWholeSeparator("ab de fg", null) = ["ab", "de", "fg"]
3248    * StringUtils.splitByWholeSeparator("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3249    * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3250    * </pre>
3251    *
3252    * @param str the String to parse, may be null
3253    * @param separator String containing the String to be used as a delimiter,
3254    * {@code null} splits on whitespace
3255    * @return an array of parsed Strings, {@code null} if null String was input
3256    */
 
3257  5 toggle public static String[] splitByWholeSeparator(final String str, final String separator) {
3258  5 return splitByWholeSeparatorWorker( str, separator, -1, false ) ;
3259    }
3260   
3261    /**
3262    * <p>Splits the provided text into an array, separator string specified.
3263    * Returns a maximum of {@code max} substrings.</p>
3264    *
3265    * <p>The separator(s) will not be included in the returned String array.
3266    * Adjacent separators are treated as one separator.</p>
3267    *
3268    * <p>A {@code null} input String returns {@code null}.
3269    * A {@code null} separator splits on whitespace.</p>
3270    *
3271    * <pre>
3272    * StringUtils.splitByWholeSeparator(null, *, *) = null
3273    * StringUtils.splitByWholeSeparator("", *, *) = []
3274    * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
3275    * StringUtils.splitByWholeSeparator("ab de fg", null, 0) = ["ab", "de", "fg"]
3276    * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
3277    * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3278    * StringUtils.splitByWholeSeparator("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3279    * </pre>
3280    *
3281    * @param str the String to parse, may be null
3282    * @param separator String containing the String to be used as a delimiter,
3283    * {@code null} splits on whitespace
3284    * @param max the maximum number of elements to include in the returned
3285    * array. A zero or negative value implies no limit.
3286    * @return an array of parsed Strings, {@code null} if null String was input
3287    */
 
3288  4 toggle public static String[] splitByWholeSeparator( final String str, final String separator, final int max) {
3289  4 return splitByWholeSeparatorWorker(str, separator, max, false);
3290    }
3291   
3292    /**
3293    * <p>Splits the provided text into an array, separator string specified. </p>
3294    *
3295    * <p>The separator is not included in the returned String array.
3296    * Adjacent separators are treated as separators for empty tokens.
3297    * For more control over the split use the StrTokenizer class.</p>
3298    *
3299    * <p>A {@code null} input String returns {@code null}.
3300    * A {@code null} separator splits on whitespace.</p>
3301    *
3302    * <pre>
3303    * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *) = null
3304    * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *) = []
3305    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "de", "fg"]
3306    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null) = ["ab", "", "", "de", "fg"]
3307    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3308    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-") = ["ab", "cd", "ef"]
3309    * </pre>
3310    *
3311    * @param str the String to parse, may be null
3312    * @param separator String containing the String to be used as a delimiter,
3313    * {@code null} splits on whitespace
3314    * @return an array of parsed Strings, {@code null} if null String was input
3315    * @since 2.4
3316    */
 
3317  5 toggle public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) {
3318  5 return splitByWholeSeparatorWorker(str, separator, -1, true);
3319    }
3320   
3321    /**
3322    * <p>Splits the provided text into an array, separator string specified.
3323    * Returns a maximum of {@code max} substrings.</p>
3324    *
3325    * <p>The separator is not included in the returned String array.
3326    * Adjacent separators are treated as separators for empty tokens.
3327    * For more control over the split use the StrTokenizer class.</p>
3328    *
3329    * <p>A {@code null} input String returns {@code null}.
3330    * A {@code null} separator splits on whitespace.</p>
3331    *
3332    * <pre>
3333    * StringUtils.splitByWholeSeparatorPreserveAllTokens(null, *, *) = null
3334    * StringUtils.splitByWholeSeparatorPreserveAllTokens("", *, *) = []
3335    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "de", "fg"]
3336    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab de fg", null, 0) = ["ab", "", "", "de", "fg"]
3337    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
3338    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 5) = ["ab", "cd", "ef"]
3339    * StringUtils.splitByWholeSeparatorPreserveAllTokens("ab-!-cd-!-ef", "-!-", 2) = ["ab", "cd-!-ef"]
3340    * </pre>
3341    *
3342    * @param str the String to parse, may be null
3343    * @param separator String containing the String to be used as a delimiter,
3344    * {@code null} splits on whitespace
3345    * @param max the maximum number of elements to include in the returned
3346    * array. A zero or negative value implies no limit.
3347    * @return an array of parsed Strings, {@code null} if null String was input
3348    * @since 2.4
3349    */
 
3350  6 toggle public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) {
3351  6 return splitByWholeSeparatorWorker(str, separator, max, true);
3352    }
3353   
3354    /**
3355    * Performs the logic for the {@code splitByWholeSeparatorPreserveAllTokens} methods.
3356    *
3357    * @param str the String to parse, may be {@code null}
3358    * @param separator String containing the String to be used as a delimiter,
3359    * {@code null} splits on whitespace
3360    * @param max the maximum number of elements to include in the returned
3361    * array. A zero or negative value implies no limit.
3362    * @param preserveAllTokens if {@code true}, adjacent separators are
3363    * treated as empty token separators; if {@code false}, adjacent
3364    * separators are treated as one separator.
3365    * @return an array of parsed Strings, {@code null} if null String input
3366    * @since 2.4
3367    */
 
3368  20 toggle private static String[] splitByWholeSeparatorWorker(
3369    final String str, final String separator, final int max, final boolean preserveAllTokens) {
3370  20 if (str == null) {
3371  4 return null;
3372    }
3373   
3374  16 final int len = str.length();
3375   
3376  16 if (len == 0) {
3377  4 return ArrayUtils.EMPTY_STRING_ARRAY;
3378    }
3379   
3380  12 if (separator == null || EMPTY.equals(separator)) {
3381    // Split on whitespace.
3382  4 return splitWorker(str, null, max, preserveAllTokens);
3383    }
3384   
3385  8 final int separatorLength = separator.length();
3386   
3387  8 final ArrayList<String> substrings = new ArrayList<>();
3388  8 int numberOfSubstrings = 0;
3389  8 int beg = 0;
3390  8 int end = 0;
3391  50 while (end < len) {
3392  42 end = str.indexOf(separator, beg);
3393   
3394  42 if (end > -1) {
3395  36 if (end > beg) {
3396  19 numberOfSubstrings += 1;
3397   
3398  19 if (numberOfSubstrings == max) {
3399  1 end = len;
3400  1 substrings.add(str.substring(beg));
3401    } else {
3402    // The following is OK, because String.substring( beg, end ) excludes
3403    // the character at the position 'end'.
3404  18 substrings.add(str.substring(beg, end));
3405   
3406    // Set the starting point for the next search.
3407    // The following is equivalent to beg = end + (separatorLength - 1) + 1,
3408    // which is the right calculation:
3409  18 beg = end + separatorLength;
3410    }
3411    } else {
3412    // We found a consecutive occurrence of the separator, so skip it.
3413  17 if (preserveAllTokens) {
3414  16 numberOfSubstrings += 1;
3415  16 if (numberOfSubstrings == max) {
3416  1 end = len;
3417  1 substrings.add(str.substring(beg));
3418    } else {
3419  15 substrings.add(EMPTY);
3420    }
3421    }
3422  17 beg = end + separatorLength;
3423    }
3424    } else {
3425    // String.substring( beg ) goes from 'beg' to the end of the String.
3426  6 substrings.add(str.substring(beg));
3427  6 end = len;
3428    }
3429    }
3430   
3431  8 return substrings.toArray(new String[substrings.size()]);
3432    }
3433   
3434    // -----------------------------------------------------------------------
3435    /**
3436    * <p>Splits the provided text into an array, using whitespace as the
3437    * separator, preserving all tokens, including empty tokens created by
3438    * adjacent separators. This is an alternative to using StringTokenizer.
3439    * Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
3440    *
3441    * <p>The separator is not included in the returned String array.
3442    * Adjacent separators are treated as separators for empty tokens.
3443    * For more control over the split use the StrTokenizer class.</p>
3444    *
3445    * <p>A {@code null} input String returns {@code null}.</p>
3446    *
3447    * <pre>
3448    * StringUtils.splitPreserveAllTokens(null) = null
3449    * StringUtils.splitPreserveAllTokens("") = []
3450    * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "def"]
3451    * StringUtils.splitPreserveAllTokens("abc def") = ["abc", "", "def"]
3452    * StringUtils.splitPreserveAllTokens(" abc ") = ["", "abc", ""]
3453    * </pre>
3454    *
3455    * @param str the String to parse, may be {@code null}
3456    * @return an array of parsed Strings, {@code null} if null String input
3457    * @since 2.1
3458    */
 
3459  11 toggle public static String[] splitPreserveAllTokens(final String str) {
3460  11 return splitWorker(str, null, -1, true);
3461    }
3462   
3463    /**
3464    * <p>Splits the provided text into an array, separator specified,
3465    * preserving all tokens, including empty tokens created by adjacent
3466    * separators. This is an alternative to using StringTokenizer.</p>
3467    *
3468    * <p>The separator is not included in the returned String array.
3469    * Adjacent separators are treated as separators for empty tokens.
3470    * For more control over the split use the StrTokenizer class.</p>
3471    *
3472    * <p>A {@code null} input String returns {@code null}.</p>
3473    *
3474    * <pre>
3475    * StringUtils.splitPreserveAllTokens(null, *) = null
3476    * StringUtils.splitPreserveAllTokens("", *) = []
3477    * StringUtils.splitPreserveAllTokens("a.b.c", '.') = ["a", "b", "c"]
3478    * StringUtils.splitPreserveAllTokens("a..b.c", '.') = ["a", "", "b", "c"]
3479    * StringUtils.splitPreserveAllTokens("a:b:c", '.') = ["a:b:c"]
3480    * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
3481    * StringUtils.splitPreserveAllTokens("a b c", ' ') = ["a", "b", "c"]
3482    * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", ""]
3483    * StringUtils.splitPreserveAllTokens("a b c ", ' ') = ["a", "b", "c", "", ""]
3484    * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", a", "b", "c"]
3485    * StringUtils.splitPreserveAllTokens(" a b c", ' ') = ["", "", a", "b", "c"]
3486    * StringUtils.splitPreserveAllTokens(" a b c ", ' ') = ["", a", "b", "c", ""]
3487    * </pre>
3488    *
3489    * @param str the String to parse, may be {@code null}
3490    * @param separatorChar the character used as the delimiter,
3491    * {@code null} splits on whitespace
3492    * @return an array of parsed Strings, {@code null} if null String input
3493    * @since 2.1
3494    */
 
3495  15 toggle public static String[] splitPreserveAllTokens(final String str, final char separatorChar) {
3496  15 return splitWorker(str, separatorChar, true);
3497    }
3498   
3499    /**
3500    * Performs the logic for the {@code split} and
3501    * {@code splitPreserveAllTokens} methods that do not return a
3502    * maximum array length.
3503    *
3504    * @param str the String to parse, may be {@code null}
3505    * @param separatorChar the separate character
3506    * @param preserveAllTokens if {@code true}, adjacent separators are
3507    * treated as empty token separators; if {@code false}, adjacent
3508    * separators are treated as one separator.
3509    * @return an array of parsed Strings, {@code null} if null String input
3510    */
 
3511  24 toggle private static String[] splitWorker(final String str, final char separatorChar, final boolean preserveAllTokens) {
3512    // Performance tuned for 2.0 (JDK1.4)
3513   
3514  24 if (str == null) {
3515  2 return null;
3516    }
3517  22 final int len = str.length();
3518  22 if (len == 0) {
3519  4 return ArrayUtils.EMPTY_STRING_ARRAY;
3520    }
3521  18 final List<String> list = new ArrayList<>();
3522  18 int i = 0, start = 0;
3523  18 boolean match = false;
3524  18 boolean lastMatch = false;
3525  114 while (i < len) {
3526  96 if (str.charAt(i) == separatorChar) {
3527  47 if (match || preserveAllTokens) {
3528  45 list.add(str.substring(start, i));
3529  45 match = false;
3530  45 lastMatch = true;
3531    }
3532  47 start = ++i;
3533  47 continue;
3534    }
3535  49 lastMatch = false;
3536  49 match = true;
3537  49 i++;
3538    }
3539  18 if (match || preserveAllTokens && lastMatch) {
3540  17 list.add(str.substring(start, i));
3541    }
3542  18 return list.toArray(new String[list.size()]);
3543    }
3544   
3545    /**
3546    * <p>Splits the provided text into an array, separators specified,
3547    * preserving all tokens, including empty tokens created by adjacent
3548    * separators. This is an alternative to using StringTokenizer.</p>
3549    *
3550    * <p>The separator is not included in the returned String array.
3551    * Adjacent separators are treated as separators for empty tokens.
3552    * For more control over the split use the StrTokenizer class.</p>
3553    *
3554    * <p>A {@code null} input String returns {@code null}.
3555    * A {@code null} separatorChars splits on whitespace.</p>
3556    *
3557    * <pre>
3558    * StringUtils.splitPreserveAllTokens(null, *) = null
3559    * StringUtils.splitPreserveAllTokens("", *) = []
3560    * StringUtils.splitPreserveAllTokens("abc def", null) = ["abc", "def"]
3561    * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "def"]
3562    * StringUtils.splitPreserveAllTokens("abc def", " ") = ["abc", "", def"]
3563    * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":") = ["ab", "cd", "ef"]
3564    * StringUtils.splitPreserveAllTokens("ab:cd:ef:", ":") = ["ab", "cd", "ef", ""]
3565    * StringUtils.splitPreserveAllTokens("ab:cd:ef::", ":") = ["ab", "cd", "ef", "", ""]
3566    * StringUtils.splitPreserveAllTokens("ab::cd:ef", ":") = ["ab", "", cd", "ef"]
3567    * StringUtils.splitPreserveAllTokens(":cd:ef", ":") = ["", cd", "ef"]
3568    * StringUtils.splitPreserveAllTokens("::cd:ef", ":") = ["", "", cd", "ef"]
3569    * StringUtils.splitPreserveAllTokens(":cd:ef:", ":") = ["", cd", "ef", ""]
3570    * </pre>
3571    *
3572    * @param str the String to parse, may be {@code null}
3573    * @param separatorChars the characters used as the delimiters,
3574    * {@code null} splits on whitespace
3575    * @return an array of parsed Strings, {@code null} if null String input
3576    * @since 2.1
3577    */
 
3578  3128 toggle public static String[] splitPreserveAllTokens(final String str, final String separatorChars) {
3579  3128 return splitWorker(str, separatorChars, -1, true);
3580    }
3581   
3582    /**
3583    * <p>Splits the provided text into an array with a maximum length,
3584    * separators specified, preserving all tokens, including empty tokens
3585    * created by adjacent separators.</p>
3586    *
3587    * <p>The separator is not included in the returned String array.
3588    * Adjacent separators are treated as separators for empty tokens.
3589    * Adjacent separators are treated as one separator.</p>
3590    *
3591    * <p>A {@code null} input String returns {@code null}.
3592    * A {@code null} separatorChars splits on whitespace.</p>
3593    *
3594    * <p>If more than {@code max} delimited substrings are found, the last
3595    * returned string includes all characters after the first {@code max - 1}
3596    * returned strings (including separator characters).</p>
3597    *
3598    * <pre>
3599    * StringUtils.splitPreserveAllTokens(null, *, *) = null
3600    * StringUtils.splitPreserveAllTokens("", *, *) = []
3601    * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
3602    * StringUtils.splitPreserveAllTokens("ab de fg", null, 0) = ["ab", "cd", "ef"]
3603    * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0) = ["ab", "cd", "ef"]
3604    * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2) = ["ab", "cd:ef"]
3605    * StringUtils.splitPreserveAllTokens("ab de fg", null, 2) = ["ab", " de fg"]
3606    * StringUtils.splitPreserveAllTokens("ab de fg", null, 3) = ["ab", "", " de fg"]
3607    * StringUtils.splitPreserveAllTokens("ab de fg", null, 4) = ["ab", "", "", "de fg"]
3608    * </pre>
3609    *
3610    * @param str the String to parse, may be {@code null}
3611    * @param separatorChars the characters used as the delimiters,
3612    * {@code null} splits on whitespace
3613    * @param max the maximum number of elements to include in the
3614    * array. A zero or negative value implies no limit
3615    * @return an array of parsed Strings, {@code null} if null String input
3616    * @since 2.1
3617    */
 
3618  6265 toggle public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) {
3619  6265 return splitWorker(str, separatorChars, max, true);
3620    }
3621   
3622    /**
3623    * Performs the logic for the {@code split} and
3624    * {@code splitPreserveAllTokens} methods that return a maximum array
3625    * length.
3626    *
3627    * @param str the String to parse, may be {@code null}
3628    * @param separatorChars the separate character
3629    * @param max the maximum number of elements to include in the
3630    * array. A zero or negative value implies no limit.
3631    * @param preserveAllTokens if {@code true}, adjacent separators are
3632    * treated as empty token separators; if {@code false}, adjacent
3633    * separators are treated as one separator.
3634    * @return an array of parsed Strings, {@code null} if null String input
3635    */
 
3636  18797 toggle private static String[] splitWorker(final String str, final String separatorChars, final int max, final boolean preserveAllTokens) {
3637    // Performance tuned for 2.0 (JDK1.4)
3638    // Direct code is quicker than StringTokenizer.
3639    // Also, StringTokenizer uses isSpace() not isWhitespace()
3640   
3641  18797 if (str == null) {
3642  6 return null;
3643    }
3644  18791 final int len = str.length();
3645  18791 if (len == 0) {
3646  6 return ArrayUtils.EMPTY_STRING_ARRAY;
3647    }
3648  18785 final List<String> list = new ArrayList<>();
3649  18785 int sizePlus1 = 1;
3650  18785 int i = 0, start = 0;
3651  18785 boolean match = false;
3652  18785 boolean lastMatch = false;
3653  18785 if (separatorChars == null) {
3654    // Null separator means use whitespace
3655  56428 while (i < len) {
3656  47047 if (Character.isWhitespace(str.charAt(i))) {
3657  21948 if (match || preserveAllTokens) {
3658  18795 lastMatch = true;
3659  18795 if (sizePlus1++ == max) {
3660  3126 i = len;
3661  3126 lastMatch = false;
3662    }
3663  18795 list.add(str.substring(start, i));
3664  18795 match = false;
3665    }
3666  21948 start = ++i;
3667  21948 continue;
3668    }
3669  25099 lastMatch = false;
3670  25099 match = true;
3671  25099 i++;
3672    }
3673  9404 } else if (separatorChars.length() == 1) {
3674    // Optimise 1 character case
3675  9392 final char sep = separatorChars.charAt(0);
3676  56364 while (i < len) {
3677  46972 if (str.charAt(i) == sep) {
3678  21922 if (match || preserveAllTokens) {
3679  18794 lastMatch = true;
3680  18794 if (sizePlus1++ == max) {
3681  3136 i = len;
3682  3136 lastMatch = false;
3683    }
3684  18794 list.add(str.substring(start, i));
3685  18794 match = false;
3686    }
3687  21922 start = ++i;
3688  21922 continue;
3689    }
3690  25050 lastMatch = false;
3691  25050 match = true;
3692  25050 i++;
3693    }
3694    } else {
3695    // standard case
3696  72 while (i < len) {
3697  60 if (separatorChars.indexOf(str.charAt(i)) >= 0) {
3698  28 if (match || preserveAllTokens) {
3699  24 lastMatch = true;
3700  24 if (sizePlus1++ == max) {
3701  4 i = len;
3702  4 lastMatch = false;
3703    }
3704  24 list.add(str.substring(start, i));
3705  24 match = false;
3706    }
3707  28 start = ++i;
3708  28 continue;
3709    }
3710  32 lastMatch = false;
3711  32 match = true;
3712  32 i++;
3713    }
3714    }
3715  18785 if (match || preserveAllTokens && lastMatch) {
3716  10955 list.add(str.substring(start, i));
3717    }
3718  18785 return list.toArray(new String[list.size()]);
3719    }
3720   
3721    /**
3722    * <p>Splits a String by Character type as returned by
3723    * {@code java.lang.Character.getType(char)}. Groups of contiguous
3724    * characters of the same type are returned as complete tokens.
3725    * <pre>
3726    * StringUtils.splitByCharacterType(null) = null
3727    * StringUtils.splitByCharacterType("") = []
3728    * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3729    * StringUtils.splitByCharacterType("ab de fg") = ["ab", " ", "de", " ", "fg"]
3730    * StringUtils.splitByCharacterType("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3731    * StringUtils.splitByCharacterType("number5") = ["number", "5"]
3732    * StringUtils.splitByCharacterType("fooBar") = ["foo", "B", "ar"]
3733    * StringUtils.splitByCharacterType("foo200Bar") = ["foo", "200", "B", "ar"]
3734    * StringUtils.splitByCharacterType("ASFRules") = ["ASFR", "ules"]
3735    * </pre>
3736    * @param str the String to split, may be {@code null}
3737    * @return an array of parsed Strings, {@code null} if null String input
3738    * @since 2.4
3739    */
 
3740  9 toggle public static String[] splitByCharacterType(final String str) {
3741  9 return splitByCharacterType(str, false);
3742    }
3743   
3744    /**
3745    * <p>Splits a String by Character type as returned by
3746    * {@code java.lang.Character.getType(char)}. Groups of contiguous
3747    * characters of the same type are returned as complete tokens, with the
3748    * following exception: the character of type
3749    * {@code Character.UPPERCASE_LETTER}, if any, immediately
3750    * preceding a token of type {@code Character.LOWERCASE_LETTER}
3751    * will belong to the following token rather than to the preceding, if any,
3752    * {@code Character.UPPERCASE_LETTER} token.
3753    * <pre>
3754    * StringUtils.splitByCharacterTypeCamelCase(null) = null
3755    * StringUtils.splitByCharacterTypeCamelCase("") = []
3756    * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3757    * StringUtils.splitByCharacterTypeCamelCase("ab de fg") = ["ab", " ", "de", " ", "fg"]
3758    * StringUtils.splitByCharacterTypeCamelCase("ab:cd:ef") = ["ab", ":", "cd", ":", "ef"]
3759    * StringUtils.splitByCharacterTypeCamelCase("number5") = ["number", "5"]
3760    * StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
3761    * StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
3762    * StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
3763    * </pre>
3764    * @param str the String to split, may be {@code null}
3765    * @return an array of parsed Strings, {@code null} if null String input
3766    * @since 2.4
3767    */
 
3768  9 toggle public static String[] splitByCharacterTypeCamelCase(final String str) {
3769  9 return splitByCharacterType(str, true);
3770    }
3771   
3772    /**
3773    * <p>Splits a String by Character type as returned by
3774    * {@code java.lang.Character.getType(char)}. Groups of contiguous
3775    * characters of the same type are returned as complete tokens, with the
3776    * following exception: if {@code camelCase} is {@code true},
3777    * the character of type {@code Character.UPPERCASE_LETTER}, if any,
3778    * immediately preceding a token of type {@code Character.LOWERCASE_LETTER}
3779    * will belong to the following token rather than to the preceding, if any,
3780    * {@code Character.UPPERCASE_LETTER} token.
3781    * @param str the String to split, may be {@code null}
3782    * @param camelCase whether to use so-called "camel-case" for letter types
3783    * @return an array of parsed Strings, {@code null} if null String input
3784    * @since 2.4
3785    */
 
3786  18 toggle private static String[] splitByCharacterType(final String str, final boolean camelCase) {
3787  18 if (str == null) {
3788  2 return null;
3789    }
3790  16 if (str.isEmpty()) {
3791  2 return ArrayUtils.EMPTY_STRING_ARRAY;
3792    }
3793  14 final char[] c = str.toCharArray();
3794  14 final List<String> list = new ArrayList<>();
3795  14 int tokenStart = 0;
3796  14 int currentType = Character.getType(c[tokenStart]);
3797  112 for (int pos = tokenStart + 1; pos < c.length; pos++) {
3798  98 final int type = Character.getType(c[pos]);
3799  98 if (type == currentType) {
3800  60 continue;
3801    }
3802  38 if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
3803  3 final int newTokenStart = pos - 1;
3804  3 if (newTokenStart != tokenStart) {
3805  1 list.add(new String(c, tokenStart, newTokenStart - tokenStart));
3806  1 tokenStart = newTokenStart;
3807    }
3808    } else {
3809  35 list.add(new String(c, tokenStart, pos - tokenStart));
3810  35 tokenStart = pos;
3811    }
3812  38 currentType = type;
3813    }
3814  14 list.add(new String(c, tokenStart, c.length - tokenStart));
3815  14 return list.toArray(new String[list.size()]);
3816    }
3817   
3818    // Joining
3819    //-----------------------------------------------------------------------
3820    /**
3821    * <p>Joins the elements of the provided array into a single String
3822    * containing the provided list of elements.</p>
3823    *
3824    * <p>No separator is added to the joined String.
3825    * Null objects or empty strings within the array are represented by
3826    * empty strings.</p>
3827    *
3828    * <pre>
3829    * StringUtils.join(null) = null
3830    * StringUtils.join([]) = ""
3831    * StringUtils.join([null]) = ""
3832    * StringUtils.join(["a", "b", "c"]) = "abc"
3833    * StringUtils.join([null, "", "a"]) = "a"
3834    * </pre>
3835    *
3836    * @param <T> the specific type of values to join together
3837    * @param elements the values to join together, may be null
3838    * @return the joined String, {@code null} if null array input
3839    * @since 2.0
3840    * @since 3.0 Changed signature to use varargs
3841    */
 
3842  24 toggle @SafeVarargs
3843    public static <T> String join(final T... elements) {
3844  24 return join(elements, null);
3845    }
3846   
3847    /**
3848    * <p>Joins the elements of the provided array into a single String
3849    * containing the provided list of elements.</p>
3850    *
3851    * <p>No delimiter is added before or after the list.
3852    * Null objects or empty strings within the array are represented by
3853    * empty strings.</p>
3854    *
3855    * <pre>
3856    * StringUtils.join(null, *) = null
3857    * StringUtils.join([], *) = ""
3858    * StringUtils.join([null], *) = ""
3859    * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
3860    * StringUtils.join(["a", "b", "c"], null) = "abc"
3861    * StringUtils.join([null, "", "a"], ';') = ";;a"
3862    * </pre>
3863    *
3864    * @param array the array of values to join together, may be null
3865    * @param separator the separator character to use
3866    * @return the joined String, {@code null} if null array input
3867    * @since 2.0
3868    */
 
3869  16 toggle public static String join(final Object[] array, final char separator) {
3870  16 if (array == null) {
3871  1 return null;
3872    }
3873  15 return join(array, separator, 0, array.length);
3874    }
3875   
3876    /**
3877    * <p>
3878    * Joins the elements of the provided array into a single String containing the provided list of elements.
3879    * </p>
3880    *
3881    * <p>
3882    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3883    * by empty strings.
3884    * </p>
3885    *
3886    * <pre>
3887    * StringUtils.join(null, *) = null
3888    * StringUtils.join([], *) = ""
3889    * StringUtils.join([null], *) = ""
3890    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3891    * StringUtils.join([1, 2, 3], null) = "123"
3892    * </pre>
3893    *
3894    * @param array
3895    * the array of values to join together, may be null
3896    * @param separator
3897    * the separator character to use
3898    * @return the joined String, {@code null} if null array input
3899    * @since 3.2
3900    */
 
3901  2 toggle public static String join(final long[] array, final char separator) {
3902  2 if (array == null) {
3903  1 return null;
3904    }
3905  1 return join(array, separator, 0, array.length);
3906    }
3907   
3908    /**
3909    * <p>
3910    * Joins the elements of the provided array into a single String containing the provided list of elements.
3911    * </p>
3912    *
3913    * <p>
3914    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3915    * by empty strings.
3916    * </p>
3917    *
3918    * <pre>
3919    * StringUtils.join(null, *) = null
3920    * StringUtils.join([], *) = ""
3921    * StringUtils.join([null], *) = ""
3922    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3923    * StringUtils.join([1, 2, 3], null) = "123"
3924    * </pre>
3925    *
3926    * @param array
3927    * the array of values to join together, may be null
3928    * @param separator
3929    * the separator character to use
3930    * @return the joined String, {@code null} if null array input
3931    * @since 3.2
3932    */
 
3933  2 toggle public static String join(final int[] array, final char separator) {
3934  2 if (array == null) {
3935  1 return null;
3936    }
3937  1 return join(array, separator, 0, array.length);
3938    }
3939   
3940    /**
3941    * <p>
3942    * Joins the elements of the provided array into a single String containing the provided list of elements.
3943    * </p>
3944    *
3945    * <p>
3946    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3947    * by empty strings.
3948    * </p>
3949    *
3950    * <pre>
3951    * StringUtils.join(null, *) = null
3952    * StringUtils.join([], *) = ""
3953    * StringUtils.join([null], *) = ""
3954    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3955    * StringUtils.join([1, 2, 3], null) = "123"
3956    * </pre>
3957    *
3958    * @param array
3959    * the array of values to join together, may be null
3960    * @param separator
3961    * the separator character to use
3962    * @return the joined String, {@code null} if null array input
3963    * @since 3.2
3964    */
 
3965  2 toggle public static String join(final short[] array, final char separator) {
3966  2 if (array == null) {
3967  1 return null;
3968    }
3969  1 return join(array, separator, 0, array.length);
3970    }
3971   
3972    /**
3973    * <p>
3974    * Joins the elements of the provided array into a single String containing the provided list of elements.
3975    * </p>
3976    *
3977    * <p>
3978    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
3979    * by empty strings.
3980    * </p>
3981    *
3982    * <pre>
3983    * StringUtils.join(null, *) = null
3984    * StringUtils.join([], *) = ""
3985    * StringUtils.join([null], *) = ""
3986    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
3987    * StringUtils.join([1, 2, 3], null) = "123"
3988    * </pre>
3989    *
3990    * @param array
3991    * the array of values to join together, may be null
3992    * @param separator
3993    * the separator character to use
3994    * @return the joined String, {@code null} if null array input
3995    * @since 3.2
3996    */
 
3997  2 toggle public static String join(final byte[] array, final char separator) {
3998  2 if (array == null) {
3999  1 return null;
4000    }
4001  1 return join(array, separator, 0, array.length);
4002    }
4003   
4004    /**
4005    * <p>
4006    * Joins the elements of the provided array into a single String containing the provided list of elements.
4007    * </p>
4008    *
4009    * <p>
4010    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4011    * by empty strings.
4012    * </p>
4013    *
4014    * <pre>
4015    * StringUtils.join(null, *) = null
4016    * StringUtils.join([], *) = ""
4017    * StringUtils.join([null], *) = ""
4018    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4019    * StringUtils.join([1, 2, 3], null) = "123"
4020    * </pre>
4021    *
4022    * @param array
4023    * the array of values to join together, may be null
4024    * @param separator
4025    * the separator character to use
4026    * @return the joined String, {@code null} if null array input
4027    * @since 3.2
4028    */
 
4029  2 toggle public static String join(final char[] array, final char separator) {
4030  2 if (array == null) {
4031  1 return null;
4032    }
4033  1 return join(array, separator, 0, array.length);
4034    }
4035   
4036    /**
4037    * <p>
4038    * Joins the elements of the provided array into a single String containing the provided list of elements.
4039    * </p>
4040    *
4041    * <p>
4042    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4043    * by empty strings.
4044    * </p>
4045    *
4046    * <pre>
4047    * StringUtils.join(null, *) = null
4048    * StringUtils.join([], *) = ""
4049    * StringUtils.join([null], *) = ""
4050    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4051    * StringUtils.join([1, 2, 3], null) = "123"
4052    * </pre>
4053    *
4054    * @param array
4055    * the array of values to join together, may be null
4056    * @param separator
4057    * the separator character to use
4058    * @return the joined String, {@code null} if null array input
4059    * @since 3.2
4060    */
 
4061  2 toggle public static String join(final float[] array, final char separator) {
4062  2 if (array == null) {
4063  1 return null;
4064    }
4065  1 return join(array, separator, 0, array.length);
4066    }
4067   
4068    /**
4069    * <p>
4070    * Joins the elements of the provided array into a single String containing the provided list of elements.
4071    * </p>
4072    *
4073    * <p>
4074    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4075    * by empty strings.
4076    * </p>
4077    *
4078    * <pre>
4079    * StringUtils.join(null, *) = null
4080    * StringUtils.join([], *) = ""
4081    * StringUtils.join([null], *) = ""
4082    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4083    * StringUtils.join([1, 2, 3], null) = "123"
4084    * </pre>
4085    *
4086    * @param array
4087    * the array of values to join together, may be null
4088    * @param separator
4089    * the separator character to use
4090    * @return the joined String, {@code null} if null array input
4091    * @since 3.2
4092    */
 
4093  2 toggle public static String join(final double[] array, final char separator) {
4094  2 if (array == null) {
4095  1 return null;
4096    }
4097  1 return join(array, separator, 0, array.length);
4098    }
4099   
4100   
4101    /**
4102    * <p>Joins the elements of the provided array into a single String
4103    * containing the provided list of elements.</p>
4104    *
4105    * <p>No delimiter is added before or after the list.
4106    * Null objects or empty strings within the array are represented by
4107    * empty strings.</p>
4108    *
4109    * <pre>
4110    * StringUtils.join(null, *) = null
4111    * StringUtils.join([], *) = ""
4112    * StringUtils.join([null], *) = ""
4113    * StringUtils.join(["a", "b", "c"], ';') = "a;b;c"
4114    * StringUtils.join(["a", "b", "c"], null) = "abc"
4115    * StringUtils.join([null, "", "a"], ';') = ";;a"
4116    * </pre>
4117    *
4118    * @param array the array of values to join together, may be null
4119    * @param separator the separator character to use
4120    * @param startIndex the first index to start joining from. It is
4121    * an error to pass in an end index past the end of the array
4122    * @param endIndex the index to stop joining from (exclusive). It is
4123    * an error to pass in an end index past the end of the array
4124    * @return the joined String, {@code null} if null array input
4125    * @since 2.0
4126    */
 
4127  22 toggle public static String join(final Object[] array, final char separator, final int startIndex, final int endIndex) {
4128  22 if (array == null) {
4129  1 return null;
4130    }
4131  21 final int noOfItems = endIndex - startIndex;
4132  21 if (noOfItems <= 0) {
4133  4 return EMPTY;
4134    }
4135  17 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4136  55 for (int i = startIndex; i < endIndex; i++) {
4137  38 if (i > startIndex) {
4138  21 buf.append(separator);
4139    }
4140  38 if (array[i] != null) {
4141  36 buf.append(array[i]);
4142    }
4143    }
4144  17 return buf.toString();
4145    }
4146   
4147    /**
4148    * <p>
4149    * Joins the elements of the provided array into a single String containing the provided list of elements.
4150    * </p>
4151    *
4152    * <p>
4153    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4154    * by empty strings.
4155    * </p>
4156    *
4157    * <pre>
4158    * StringUtils.join(null, *) = null
4159    * StringUtils.join([], *) = ""
4160    * StringUtils.join([null], *) = ""
4161    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4162    * StringUtils.join([1, 2, 3], null) = "123"
4163    * </pre>
4164    *
4165    * @param array
4166    * the array of values to join together, may be null
4167    * @param separator
4168    * the separator character to use
4169    * @param startIndex
4170    * the first index to start joining from. It is an error to pass in an end index past the end of the
4171    * array
4172    * @param endIndex
4173    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4174    * the array
4175    * @return the joined String, {@code null} if null array input
4176    * @since 3.2
4177    */
 
4178  5 toggle public static String join(final long[] array, final char separator, final int startIndex, final int endIndex) {
4179  5 if (array == null) {
4180  1 return null;
4181    }
4182  4 final int noOfItems = endIndex - startIndex;
4183  4 if (noOfItems <= 0) {
4184  2 return EMPTY;
4185    }
4186  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4187  5 for (int i = startIndex; i < endIndex; i++) {
4188  3 if (i > startIndex) {
4189  1 buf.append(separator);
4190    }
4191  3 buf.append(array[i]);
4192    }
4193  2 return buf.toString();
4194    }
4195   
4196    /**
4197    * <p>
4198    * Joins the elements of the provided array into a single String containing the provided list of elements.
4199    * </p>
4200    *
4201    * <p>
4202    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4203    * by empty strings.
4204    * </p>
4205    *
4206    * <pre>
4207    * StringUtils.join(null, *) = null
4208    * StringUtils.join([], *) = ""
4209    * StringUtils.join([null], *) = ""
4210    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4211    * StringUtils.join([1, 2, 3], null) = "123"
4212    * </pre>
4213    *
4214    * @param array
4215    * the array of values to join together, may be null
4216    * @param separator
4217    * the separator character to use
4218    * @param startIndex
4219    * the first index to start joining from. It is an error to pass in an end index past the end of the
4220    * array
4221    * @param endIndex
4222    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4223    * the array
4224    * @return the joined String, {@code null} if null array input
4225    * @since 3.2
4226    */
 
4227  5 toggle public static String join(final int[] array, final char separator, final int startIndex, final int endIndex) {
4228  5 if (array == null) {
4229  1 return null;
4230    }
4231  4 final int noOfItems = endIndex - startIndex;
4232  4 if (noOfItems <= 0) {
4233  2 return EMPTY;
4234    }
4235  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4236  5 for (int i = startIndex; i < endIndex; i++) {
4237  3 if (i > startIndex) {
4238  1 buf.append(separator);
4239    }
4240  3 buf.append(array[i]);
4241    }
4242  2 return buf.toString();
4243    }
4244   
4245    /**
4246    * <p>
4247    * Joins the elements of the provided array into a single String containing the provided list of elements.
4248    * </p>
4249    *
4250    * <p>
4251    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4252    * by empty strings.
4253    * </p>
4254    *
4255    * <pre>
4256    * StringUtils.join(null, *) = null
4257    * StringUtils.join([], *) = ""
4258    * StringUtils.join([null], *) = ""
4259    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4260    * StringUtils.join([1, 2, 3], null) = "123"
4261    * </pre>
4262    *
4263    * @param array
4264    * the array of values to join together, may be null
4265    * @param separator
4266    * the separator character to use
4267    * @param startIndex
4268    * the first index to start joining from. It is an error to pass in an end index past the end of the
4269    * array
4270    * @param endIndex
4271    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4272    * the array
4273    * @return the joined String, {@code null} if null array input
4274    * @since 3.2
4275    */
 
4276  5 toggle public static String join(final byte[] array, final char separator, final int startIndex, final int endIndex) {
4277  5 if (array == null) {
4278  1 return null;
4279    }
4280  4 final int noOfItems = endIndex - startIndex;
4281  4 if (noOfItems <= 0) {
4282  2 return EMPTY;
4283    }
4284  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4285  5 for (int i = startIndex; i < endIndex; i++) {
4286  3 if (i > startIndex) {
4287  1 buf.append(separator);
4288    }
4289  3 buf.append(array[i]);
4290    }
4291  2 return buf.toString();
4292    }
4293   
4294    /**
4295    * <p>
4296    * Joins the elements of the provided array into a single String containing the provided list of elements.
4297    * </p>
4298    *
4299    * <p>
4300    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4301    * by empty strings.
4302    * </p>
4303    *
4304    * <pre>
4305    * StringUtils.join(null, *) = null
4306    * StringUtils.join([], *) = ""
4307    * StringUtils.join([null], *) = ""
4308    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4309    * StringUtils.join([1, 2, 3], null) = "123"
4310    * </pre>
4311    *
4312    * @param array
4313    * the array of values to join together, may be null
4314    * @param separator
4315    * the separator character to use
4316    * @param startIndex
4317    * the first index to start joining from. It is an error to pass in an end index past the end of the
4318    * array
4319    * @param endIndex
4320    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4321    * the array
4322    * @return the joined String, {@code null} if null array input
4323    * @since 3.2
4324    */
 
4325  5 toggle public static String join(final short[] array, final char separator, final int startIndex, final int endIndex) {
4326  5 if (array == null) {
4327  1 return null;
4328    }
4329  4 final int noOfItems = endIndex - startIndex;
4330  4 if (noOfItems <= 0) {
4331  2 return EMPTY;
4332    }
4333  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4334  5 for (int i = startIndex; i < endIndex; i++) {
4335  3 if (i > startIndex) {
4336  1 buf.append(separator);
4337    }
4338  3 buf.append(array[i]);
4339    }
4340  2 return buf.toString();
4341    }
4342   
4343    /**
4344    * <p>
4345    * Joins the elements of the provided array into a single String containing the provided list of elements.
4346    * </p>
4347    *
4348    * <p>
4349    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4350    * by empty strings.
4351    * </p>
4352    *
4353    * <pre>
4354    * StringUtils.join(null, *) = null
4355    * StringUtils.join([], *) = ""
4356    * StringUtils.join([null], *) = ""
4357    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4358    * StringUtils.join([1, 2, 3], null) = "123"
4359    * </pre>
4360    *
4361    * @param array
4362    * the array of values to join together, may be null
4363    * @param separator
4364    * the separator character to use
4365    * @param startIndex
4366    * the first index to start joining from. It is an error to pass in an end index past the end of the
4367    * array
4368    * @param endIndex
4369    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4370    * the array
4371    * @return the joined String, {@code null} if null array input
4372    * @since 3.2
4373    */
 
4374  5 toggle public static String join(final char[] array, final char separator, final int startIndex, final int endIndex) {
4375  5 if (array == null) {
4376  1 return null;
4377    }
4378  4 final int noOfItems = endIndex - startIndex;
4379  4 if (noOfItems <= 0) {
4380  2 return EMPTY;
4381    }
4382  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4383  5 for (int i = startIndex; i < endIndex; i++) {
4384  3 if (i > startIndex) {
4385  1 buf.append(separator);
4386    }
4387  3 buf.append(array[i]);
4388    }
4389  2 return buf.toString();
4390    }
4391   
4392    /**
4393    * <p>
4394    * Joins the elements of the provided array into a single String containing the provided list of elements.
4395    * </p>
4396    *
4397    * <p>
4398    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4399    * by empty strings.
4400    * </p>
4401    *
4402    * <pre>
4403    * StringUtils.join(null, *) = null
4404    * StringUtils.join([], *) = ""
4405    * StringUtils.join([null], *) = ""
4406    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4407    * StringUtils.join([1, 2, 3], null) = "123"
4408    * </pre>
4409    *
4410    * @param array
4411    * the array of values to join together, may be null
4412    * @param separator
4413    * the separator character to use
4414    * @param startIndex
4415    * the first index to start joining from. It is an error to pass in an end index past the end of the
4416    * array
4417    * @param endIndex
4418    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4419    * the array
4420    * @return the joined String, {@code null} if null array input
4421    * @since 3.2
4422    */
 
4423  5 toggle public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
4424  5 if (array == null) {
4425  1 return null;
4426    }
4427  4 final int noOfItems = endIndex - startIndex;
4428  4 if (noOfItems <= 0) {
4429  2 return EMPTY;
4430    }
4431  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4432  5 for (int i = startIndex; i < endIndex; i++) {
4433  3 if (i > startIndex) {
4434  1 buf.append(separator);
4435    }
4436  3 buf.append(array[i]);
4437    }
4438  2 return buf.toString();
4439    }
4440   
4441    /**
4442    * <p>
4443    * Joins the elements of the provided array into a single String containing the provided list of elements.
4444    * </p>
4445    *
4446    * <p>
4447    * No delimiter is added before or after the list. Null objects or empty strings within the array are represented
4448    * by empty strings.
4449    * </p>
4450    *
4451    * <pre>
4452    * StringUtils.join(null, *) = null
4453    * StringUtils.join([], *) = ""
4454    * StringUtils.join([null], *) = ""
4455    * StringUtils.join([1, 2, 3], ';') = "1;2;3"
4456    * StringUtils.join([1, 2, 3], null) = "123"
4457    * </pre>
4458    *
4459    * @param array
4460    * the array of values to join together, may be null
4461    * @param separator
4462    * the separator character to use
4463    * @param startIndex
4464    * the first index to start joining from. It is an error to pass in an end index past the end of the
4465    * array
4466    * @param endIndex
4467    * the index to stop joining from (exclusive). It is an error to pass in an end index past the end of
4468    * the array
4469    * @return the joined String, {@code null} if null array input
4470    * @since 3.2
4471    */
 
4472  5 toggle public static String join(final float[] array, final char separator, final int startIndex, final int endIndex) {
4473  5 if (array == null) {
4474  1 return null;
4475    }
4476  4 final int noOfItems = endIndex - startIndex;
4477  4 if (noOfItems <= 0) {
4478  2 return EMPTY;
4479    }
4480  2 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4481  5 for (int i = startIndex; i < endIndex; i++) {
4482  3 if (i > startIndex) {
4483  1 buf.append(separator);
4484    }
4485  3 buf.append(array[i]);
4486    }
4487  2 return buf.toString();
4488    }
4489   
4490   
4491    /**
4492    * <p>Joins the elements of the provided array into a single String
4493    * containing the provided list of elements.</p>
4494    *
4495    * <p>No delimiter is added before or after the list.
4496    * A {@code null} separator is the same as an empty String ("").
4497    * Null objects or empty strings within the array are represented by
4498    * empty strings.</p>
4499    *
4500    * <pre>
4501    * StringUtils.join(null, *) = null
4502    * StringUtils.join([], *) = ""
4503    * StringUtils.join([null], *) = ""
4504    * StringUtils.join(["a", "b", "c"], "--") = "a--b--c"
4505    * StringUtils.join(["a", "b", "c"], null) = "abc"
4506    * StringUtils.join(["a", "b", "c"], "") = "abc"
4507    * StringUtils.join([null, "", "a"], ',') = ",,a"
4508    * </pre>
4509    *
4510    * @param array the array of values to join together, may be null
4511    * @param separator the separator character to use, null treated as ""
4512    * @return the joined String, {@code null} if null array input
4513    */
 
4514  34 toggle public static String join(final Object[] array, final String separator) {
4515  34 if (array == null) {
4516  3 return null;
4517    }
4518  31 return join(array, separator, 0, array.length);
4519    }
4520   
4521    /**
4522    * <p>Joins the elements of the provided array into a single String
4523    * containing the provided list of elements.</p>
4524    *
4525    * <p>No delimiter is added before or after the list.
4526    * A {@code null} separator is the same as an empty String ("").
4527    * Null objects or empty strings within the array are represented by
4528    * empty strings.</p>
4529    *
4530    * <pre>
4531    * StringUtils.join(null, *, *, *) = null
4532    * StringUtils.join([], *, *, *) = ""
4533    * StringUtils.join([null], *, *, *) = ""
4534    * StringUtils.join(["a", "b", "c"], "--", 0, 3) = "a--b--c"
4535    * StringUtils.join(["a", "b", "c"], "--", 1, 3) = "b--c"
4536    * StringUtils.join(["a", "b", "c"], "--", 2, 3) = "c"
4537    * StringUtils.join(["a", "b", "c"], "--", 2, 2) = ""
4538    * StringUtils.join(["a", "b", "c"], null, 0, 3) = "abc"
4539    * StringUtils.join(["a", "b", "c"], "", 0, 3) = "abc"
4540    * StringUtils.join([null, "", "a"], ',', 0, 3) = ",,a"
4541    * </pre>
4542    *
4543    * @param array the array of values to join together, may be null
4544    * @param separator the separator character to use, null treated as ""
4545    * @param startIndex the first index to start joining from.
4546    * @param endIndex the index to stop joining from (exclusive).
4547    * @return the joined String, {@code null} if null array input; or the empty string
4548    * if {@code endIndex - startIndex <= 0}. The number of joined entries is given by
4549    * {@code endIndex - startIndex}
4550    * @throws ArrayIndexOutOfBoundsException ife<br>
4551    * {@code startIndex < 0} or <br>
4552    * {@code startIndex >= array.length()} or <br>
4553    * {@code endIndex < 0} or <br>
4554    * {@code endIndex > array.length()}
4555    */
 
4556  37 toggle public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
4557  37 if (array == null) {
4558  0 return null;
4559    }
4560  37 if (separator == null) {
4561  25 separator = EMPTY;
4562    }
4563   
4564    // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
4565    // (Assuming that all Strings are roughly equally long)
4566  37 final int noOfItems = endIndex - startIndex;
4567  37 if (noOfItems <= 0) {
4568  10 return EMPTY;
4569    }
4570   
4571  27 final StringBuilder buf = new StringBuilder(noOfItems * 16);
4572   
4573  102 for (int i = startIndex; i < endIndex; i++) {
4574  75 if (i > startIndex) {
4575  48 buf.append(separator);
4576    }
4577  75 if (array[i] != null) {
4578  66 buf.append(array[i]);
4579    }
4580    }
4581  27 return buf.toString();
4582    }
4583   
4584    /**
4585    * <p>Joins the elements of the provided {@code Iterator} into
4586    * a single String containing the provided elements.</p>
4587    *
4588    * <p>No delimiter is added before or after the list. Null objects or empty
4589    * strings within the iteration are represented by empty strings.</p>
4590    *
4591    * <p>See the examples here: {@link #join(Object[],char)}. </p>
4592    *
4593    * @param iterator the {@code Iterator} of values to join together, may be null
4594    * @param separator the separator character to use
4595    * @return the joined String, {@code null} if null iterator input
4596    * @since 2.0
4597    */
 
4598  9 toggle public static String join(final Iterator<?> iterator, final char separator) {
4599   
4600    // handle null, zero and one elements before building a buffer
4601  9 if (iterator == null) {
4602  1 return null;
4603    }
4604  8 if (!iterator.hasNext()) {
4605  2 return EMPTY;
4606    }
4607  6 final Object first = iterator.next();
4608  6 if (!iterator.hasNext()) {
4609  4 final String result = Objects.toString(first, "");
4610  4 return result;
4611    }
4612   
4613    // two or more elements
4614  2 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
4615  2 if (first != null) {
4616  2 buf.append(first);
4617    }
4618   
4619  6 while (iterator.hasNext()) {
4620  4 buf.append(separator);
4621  4 final Object obj = iterator.next();
4622  4 if (obj != null) {
4623  4 buf.append(obj);
4624    }
4625    }
4626   
4627  2 return buf.toString();
4628    }
4629   
4630    /**
4631    * <p>Joins the elements of the provided {@code Iterator} into
4632    * a single String containing the provided elements.</p>
4633    *
4634    * <p>No delimiter is added before or after the list.
4635    * A {@code null} separator is the same as an empty String ("").</p>
4636    *
4637    * <p>See the examples here: {@link #join(Object[],String)}. </p>
4638    *
4639    * @param iterator the {@code Iterator} of values to join together, may be null
4640    * @param separator the separator character to use, null treated as ""
4641    * @return the joined String, {@code null} if null iterator input
4642    */
 
4643  20 toggle public static String join(final Iterator<?> iterator, final String separator) {
4644   
4645    // handle null, zero and one elements before building a buffer
4646  20 if (iterator == null) {
4647  1 return null;
4648    }
4649  19 if (!iterator.hasNext()) {
4650  6 return EMPTY;
4651    }
4652  13 final Object first = iterator.next();
4653  13 if (!iterator.hasNext()) {
4654  7 final String result = Objects.toString(first, "");
4655  7 return result;
4656    }
4657   
4658    // two or more elements
4659  6 final StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small
4660  6 if (first != null) {
4661  6 buf.append(first);
4662    }
4663   
4664  18 while (iterator.hasNext()) {
4665  12 if (separator != null) {
4666  8 buf.append(separator);
4667    }
4668  12 final Object obj = iterator.next();
4669  12 if (obj != null) {
4670  12 buf.append(obj);
4671    }
4672    }
4673  6 return buf.toString();
4674    }
4675   
4676    /**
4677    * <p>Joins the elements of the provided {@code Iterable} into
4678    * a single String containing the provided elements.</p>
4679    *
4680    * <p>No delimiter is added before or after the list. Null objects or empty
4681    * strings within the iteration are represented by empty strings.</p>
4682    *
4683    * <p>See the examples here: {@link #join(Object[],char)}. </p>
4684    *
4685    * @param iterable the {@code Iterable} providing the values to join together, may be null
4686    * @param separator the separator character to use
4687    * @return the joined String, {@code null} if null iterator input
4688    * @since 2.3
4689    */
 
4690  5 toggle public static String join(final Iterable<?> iterable, final char separator) {
4691  5 if (iterable == null) {
4692  1 return null;
4693    }
4694  4 return join(iterable.iterator(), separator);
4695    }
4696   
4697    /**
4698    * <p>Joins the elements of the provided {@code Iterable} into
4699    * a single String containing the provided elements.</p>
4700    *
4701    * <p>No delimiter is added before or after the list.
4702    * A {@code null} separator is the same as an empty String ("").</p>
4703    *
4704    * <p>See the examples here: {@link #join(Object[],String)}. </p>
4705    *
4706    * @param iterable the {@code Iterable} providing the values to join together, may be null
4707    * @param separator the separator character to use, null treated as ""
4708    * @return the joined String, {@code null} if null iterator input
4709    * @since 2.3
4710    */
 
4711  10 toggle public static String join(final Iterable<?> iterable, final String separator) {
4712  10 if (iterable == null) {
4713  1 return null;
4714    }
4715  9 return join(iterable.iterator(), separator);
4716    }
4717   
4718    /**
4719    * <p>Joins the elements of the provided varargs into a
4720    * single String containing the provided elements.</p>
4721    *
4722    * <p>No delimiter is added before or after the list.
4723    * {@code null} elements and separator are treated as empty Strings ("").</p>
4724    *
4725    * <pre>
4726    * StringUtils.joinWith(",", {"a", "b"}) = "a,b"
4727    * StringUtils.joinWith(",", {"a", "b",""}) = "a,b,"
4728    * StringUtils.joinWith(",", {"a", null, "b"}) = "a,,b"
4729    * StringUtils.joinWith(null, {"a", "b"}) = "ab"
4730    * </pre>
4731    *
4732    * @param separator the separator character to use, null treated as ""
4733    * @param objects the varargs providing the values to join together. {@code null} elements are treated as ""
4734    * @return the joined String.
4735    * @throws java.lang.IllegalArgumentException if a null varargs is provided
4736    * @since 3.5
4737    */
 
4738  7 toggle public static String joinWith(final String separator, final Object... objects) {
4739  7 if (objects == null) {
4740  1 throw new IllegalArgumentException("Object varargs must not be null");
4741    }
4742   
4743  6 final String sanitizedSeparator = defaultString(separator, StringUtils.EMPTY);
4744   
4745  6 final StringBuilder result = new StringBuilder();
4746   
4747  6 final Iterator<Object> iterator = Arrays.asList(objects).iterator();
4748  16 while (iterator.hasNext()) {
4749  10 final String value = Objects.toString(iterator.next(), "");
4750  10 result.append(value);
4751   
4752  10 if (iterator.hasNext()) {
4753  5 result.append(sanitizedSeparator);
4754    }
4755    }
4756   
4757  6 return result.toString();
4758    }
4759   
4760    // Delete
4761    //-----------------------------------------------------------------------
4762    /**
4763    * <p>Deletes all whitespaces from a String as defined by
4764    * {@link Character#isWhitespace(char)}.</p>
4765    *
4766    * <pre>
4767    * StringUtils.deleteWhitespace(null) = null
4768    * StringUtils.deleteWhitespace("") = ""
4769    * StringUtils.deleteWhitespace("abc") = "abc"
4770    * StringUtils.deleteWhitespace(" ab c ") = "abc"
4771    * </pre>
4772    *
4773    * @param str the String to delete whitespace from, may be null
4774    * @return the String without whitespaces, {@code null} if null String input
4775    */
 
4776  129 toggle public static String deleteWhitespace(final String str) {
4777  129 if (isEmpty(str)) {
4778  3 return str;
4779    }
4780  126 final int sz = str.length();
4781  126 final char[] chs = new char[sz];
4782  126 int count = 0;
4783  2655 for (int i = 0; i < sz; i++) {
4784  2529 if (!Character.isWhitespace(str.charAt(i))) {
4785  2431 chs[count++] = str.charAt(i);
4786    }
4787    }
4788  126 if (count == sz) {
4789  118 return str;
4790    }
4791  8 return new String(chs, 0, count);
4792    }
4793   
4794    // Remove
4795    //-----------------------------------------------------------------------
4796    /**
4797    * <p>Removes a substring only if it is at the beginning of a source string,
4798    * otherwise returns the source string.</p>
4799    *
4800    * <p>A {@code null} source string will return {@code null}.
4801    * An empty ("") source string will return the empty string.
4802    * A {@code null} search string will return the source string.</p>
4803    *
4804    * <pre>
4805    * StringUtils.removeStart(null, *) = null
4806    * StringUtils.removeStart("", *) = ""
4807    * StringUtils.removeStart(*, null) = *
4808    * StringUtils.removeStart("www.domain.com", "www.") = "domain.com"
4809    * StringUtils.removeStart("domain.com", "www.") = "domain.com"
4810    * StringUtils.removeStart("www.domain.com", "domain") = "www.domain.com"
4811    * StringUtils.removeStart("abc", "") = "abc"
4812    * </pre>
4813    *
4814    * @param str the source String to search, may be null
4815    * @param remove the String to search for and remove, may be null
4816    * @return the substring with the string removed if found,
4817    * {@code null} if null String input
4818    * @since 2.1
4819    */
 
4820  10 toggle public static String removeStart(final String str, final String remove) {
4821  10 if (isEmpty(str) || isEmpty(remove)) {
4822  8 return str;
4823    }
4824  2 if (str.startsWith(remove)){
4825  1 return str.substring(remove.length());
4826    }
4827  1 return str;
4828    }
4829   
4830    /**
4831    * <p>Case insensitive removal of a substring if it is at the beginning of a source string,
4832    * otherwise returns the source string.</p>
4833    *
4834    * <p>A {@code null} source string will return {@code null}.
4835    * An empty ("") source string will return the empty string.
4836    * A {@code null} search string will return the source string.</p>
4837    *
4838    * <pre>
4839    * StringUtils.removeStartIgnoreCase(null, *) = null
4840    * StringUtils.removeStartIgnoreCase("", *) = ""
4841    * StringUtils.removeStartIgnoreCase(*, null) = *
4842    * StringUtils.removeStartIgnoreCase("www.domain.com", "www.") = "domain.com"
4843    * StringUtils.removeStartIgnoreCase("www.domain.com", "WWW.") = "domain.com"
4844    * StringUtils.removeStartIgnoreCase("domain.com", "www.") = "domain.com"
4845    * StringUtils.removeStartIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4846    * StringUtils.removeStartIgnoreCase("abc", "") = "abc"
4847    * </pre>
4848    *
4849    * @param str the source String to search, may be null
4850    * @param remove the String to search for (case insensitive) and remove, may be null
4851    * @return the substring with the string removed if found,
4852    * {@code null} if null String input
4853    * @since 2.4
4854    */
 
4855  11 toggle public static String removeStartIgnoreCase(final String str, final String remove) {
4856  11 if (isEmpty(str) || isEmpty(remove)) {
4857  8 return str;
4858    }
4859  3 if (startsWithIgnoreCase(str, remove)) {
4860  2 return str.substring(remove.length());
4861    }
4862  1 return str;
4863    }
4864   
4865    /**
4866    * <p>Removes a substring only if it is at the end of a source string,
4867    * otherwise returns the source string.</p>
4868    *
4869    * <p>A {@code null} source string will return {@code null}.
4870    * An empty ("") source string will return the empty string.
4871    * A {@code null} search string will return the source string.</p>
4872    *
4873    * <pre>
4874    * StringUtils.removeEnd(null, *) = null
4875    * StringUtils.removeEnd("", *) = ""
4876    * StringUtils.removeEnd(*, null) = *
4877    * StringUtils.removeEnd("www.domain.com", ".com.") = "www.domain.com"
4878    * StringUtils.removeEnd("www.domain.com", ".com") = "www.domain"
4879    * StringUtils.removeEnd("www.domain.com", "domain") = "www.domain.com"
4880    * StringUtils.removeEnd("abc", "") = "abc"
4881    * </pre>
4882    *
4883    * @param str the source String to search, may be null
4884    * @param remove the String to search for and remove, may be null
4885    * @return the substring with the string removed if found,
4886    * {@code null} if null String input
4887    * @since 2.1
4888    */
 
4889  29 toggle public static String removeEnd(final String str, final String remove) {
4890  29 if (isEmpty(str) || isEmpty(remove)) {
4891  18 return str;
4892    }
4893  11 if (str.endsWith(remove)) {
4894  6 return str.substring(0, str.length() - remove.length());
4895    }
4896  5 return str;
4897    }
4898   
4899    /**
4900    * <p>Case insensitive removal of a substring if it is at the end of a source string,
4901    * otherwise returns the source string.</p>
4902    *
4903    * <p>A {@code null} source string will return {@code null}.
4904    * An empty ("") source string will return the empty string.
4905    * A {@code null} search string will return the source string.</p>
4906    *
4907    * <pre>
4908    * StringUtils.removeEndIgnoreCase(null, *) = null
4909    * StringUtils.removeEndIgnoreCase("", *) = ""
4910    * StringUtils.removeEndIgnoreCase(*, null) = *
4911    * StringUtils.removeEndIgnoreCase("www.domain.com", ".com.") = "www.domain.com"
4912    * StringUtils.removeEndIgnoreCase("www.domain.com", ".com") = "www.domain"
4913    * StringUtils.removeEndIgnoreCase("www.domain.com", "domain") = "www.domain.com"
4914    * StringUtils.removeEndIgnoreCase("abc", "") = "abc"
4915    * StringUtils.removeEndIgnoreCase("www.domain.com", ".COM") = "www.domain")
4916    * StringUtils.removeEndIgnoreCase("www.domain.COM", ".com") = "www.domain")
4917    * </pre>
4918    *
4919    * @param str the source String to search, may be null
4920    * @param remove the String to search for (case insensitive) and remove, may be null
4921    * @return the substring with the string removed if found,
4922    * {@code null} if null String input
4923    * @since 2.4
4924    */
 
4925  13 toggle public static String removeEndIgnoreCase(final String str, final String remove) {
4926  13 if (isEmpty(str) || isEmpty(remove)) {
4927  8 return str;
4928    }
4929  5 if (endsWithIgnoreCase(str, remove)) {
4930  3 return str.substring(0, str.length() - remove.length());
4931    }
4932  2 return str;
4933    }
4934   
4935    /**
4936    * <p>Removes all occurrences of a substring from within the source string.</p>
4937    *
4938    * <p>A {@code null} source string will return {@code null}.
4939    * An empty ("") source string will return the empty string.
4940    * A {@code null} remove string will return the source string.
4941    * An empty ("") remove string will return the source string.</p>
4942    *
4943    * <pre>
4944    * StringUtils.remove(null, *) = null
4945    * StringUtils.remove("", *) = ""
4946    * StringUtils.remove(*, null) = *
4947    * StringUtils.remove(*, "") = *
4948    * StringUtils.remove("queued", "ue") = "qd"
4949    * StringUtils.remove("queued", "zz") = "queued"
4950    * </pre>
4951    *
4952    * @param str the source String to search, may be null
4953    * @param remove the String to search for and remove, may be null
4954    * @return the substring with the string removed if found,
4955    * {@code null} if null String input
4956    * @since 2.1
4957    */
 
4958  14 toggle public static String remove(final String str, final String remove) {
4959  14 if (isEmpty(str) || isEmpty(remove)) {
4960  12 return str;
4961    }
4962  2 return replace(str, remove, EMPTY, -1);
4963    }
4964   
4965    /**
4966    * <p>
4967    * Case insensitive removal of all occurrences of a substring from within
4968    * the source string.
4969    * </p>
4970    *
4971    * <p>
4972    * A {@code null} source string will return {@code null}. An empty ("")
4973    * source string will return the empty string. A {@code null} remove string
4974    * will return the source string. An empty ("") remove string will return
4975    * the source string.
4976    * </p>
4977    *
4978    * <pre>
4979    * StringUtils.removeIgnoreCase(null, *) = null
4980    * StringUtils.removeIgnoreCase("", *) = ""
4981    * StringUtils.removeIgnoreCase(*, null) = *
4982    * StringUtils.removeIgnoreCase(*, "") = *
4983    * StringUtils.removeIgnoreCase("queued", "ue") = "qd"
4984    * StringUtils.removeIgnoreCase("queued", "zz") = "queued"
4985    * StringUtils.removeIgnoreCase("quEUed", "UE") = "qd"
4986    * StringUtils.removeIgnoreCase("queued", "zZ") = "queued"
4987    * </pre>
4988    *
4989    * @param str
4990    * the source String to search, may be null
4991    * @param remove
4992    * the String to search for (case insensitive) and remove, may be
4993    * null
4994    * @return the substring with the string removed if found, {@code null} if
4995    * null String input
4996    * @since 3.5
4997    */
 
4998  16 toggle public static String removeIgnoreCase(final String str, final String remove) {
4999  16 if (isEmpty(str) || isEmpty(remove)) {
5000  12 return str;
5001    }
5002  4 return replaceIgnoreCase(str, remove, EMPTY, -1);
5003    }
5004   
5005    /**
5006    * <p>Removes all occurrences of a character from within the source string.</p>
5007    *
5008    * <p>A {@code null} source string will return {@code null}.
5009    * An empty ("") source string will return the empty string.</p>
5010    *
5011    * <pre>
5012    * StringUtils.remove(null, *) = null
5013    * StringUtils.remove("", *) = ""
5014    * StringUtils.remove("queued", 'u') = "qeed"
5015    * StringUtils.remove("queued", 'z') = "queued"
5016    * </pre>
5017    *
5018    * @param str the source String to search, may be null
5019    * @param remove the char to search for and remove, may be null
5020    * @return the substring with the char removed if found,
5021    * {@code null} if null String input
5022    * @since 2.1
5023    */
 
5024  8 toggle public static String remove(final String str, final char remove) {
5025  8 if (isEmpty(str) || str.indexOf(remove) == INDEX_NOT_FOUND) {
5026  7 return str;
5027    }
5028  1 final char[] chars = str.toCharArray();
5029  1 int pos = 0;
5030  7 for (int i = 0; i < chars.length; i++) {
5031  6 if (chars[i] != remove) {
5032  4 chars[pos++] = chars[i];
5033    }
5034    }
5035  1 return new String(chars, 0, pos);
5036    }
5037   
5038    /**
5039    * <p>Removes each substring of the text String that matches the given regular expression.</p>
5040    *
5041    * This method is a {@code null} safe equivalent to:
5042    * <ul>
5043    * <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
5044    * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
5045    * </ul>
5046    *
5047    * <p>A {@code null} reference passed to this method is a no-op.</p>
5048    *
5049    * <p>Unlike in the {@link #removePattern(String, String)} method, the {@link Pattern#DOTALL} option
5050    * is NOT automatically added.
5051    * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5052    * DOTALL is also know as single-line mode in Perl.</p>
5053    *
5054    * <pre>
5055    * StringUtils.removeAll(null, *) = null
5056    * StringUtils.removeAll("any", null) = "any"
5057    * StringUtils.removeAll("any", "") = "any"
5058    * StringUtils.removeAll("any", ".*") = ""
5059    * StringUtils.removeAll("any", ".+") = ""
5060    * StringUtils.removeAll("abc", ".?") = ""
5061    * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;") = "A\nB"
5062    * StringUtils.removeAll("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;") = "AB"
5063    * StringUtils.removeAll("ABCabc123abc", "[a-z]") = "ABC123"
5064    * </pre>
5065    *
5066    * @param text text to remove from, may be null
5067    * @param regex the regular expression to which this string is to be matched
5068    * @return the text with any removes processed,
5069    * {@code null} if null String input
5070    *
5071    * @throws java.util.regex.PatternSyntaxException
5072    * if the regular expression's syntax is invalid
5073    *
5074    * @see #replaceAll(String, String, String)
5075    * @see #removePattern(String, String)
5076    * @see String#replaceAll(String, String)
5077    * @see java.util.regex.Pattern
5078    * @see java.util.regex.Pattern#DOTALL
5079    * @since 3.5
5080    */
 
5081  10 toggle public static String removeAll(final String text, final String regex) {
5082  10 return replaceAll(text, regex, StringUtils.EMPTY);
5083    }
5084   
5085    /**
5086    * <p>Removes the first substring of the text string that matches the given regular expression.</p>
5087    *
5088    * This method is a {@code null} safe equivalent to:
5089    * <ul>
5090    * <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
5091    * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
5092    * </ul>
5093    *
5094    * <p>A {@code null} reference passed to this method is a no-op.</p>
5095    *
5096    * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5097    * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5098    * DOTALL is also know as single-line mode in Perl.</p>
5099    *
5100    * <pre>
5101    * StringUtils.removeFirst(null, *) = null
5102    * StringUtils.removeFirst("any", null) = "any"
5103    * StringUtils.removeFirst("any", "") = "any"
5104    * StringUtils.removeFirst("any", ".*") = ""
5105    * StringUtils.removeFirst("any", ".+") = ""
5106    * StringUtils.removeFirst("abc", ".?") = "bc"
5107    * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;") = "A\n&lt;__&gt;B"
5108    * StringUtils.removeFirst("A&lt;__&gt;\n&lt;__&gt;B", "(?s)&lt;.*&gt;") = "AB"
5109    * StringUtils.removeFirst("ABCabc123", "[a-z]") = "ABCbc123"
5110    * StringUtils.removeFirst("ABCabc123abc", "[a-z]+") = "ABC123abc"
5111    * </pre>
5112    *
5113    * @param text text to remove from, may be null
5114    * @param regex the regular expression to which this string is to be matched
5115    * @return the text with the first replacement processed,
5116    * {@code null} if null String input
5117    *
5118    * @throws java.util.regex.PatternSyntaxException
5119    * if the regular expression's syntax is invalid
5120    *
5121    * @see #replaceFirst(String, String, String)
5122    * @see String#replaceFirst(String, String)
5123    * @see java.util.regex.Pattern
5124    * @see java.util.regex.Pattern#DOTALL
5125    * @since 3.5
5126    */
 
5127  11 toggle public static String removeFirst(final String text, final String regex) {
5128  11 return replaceFirst(text, regex, StringUtils.EMPTY);
5129    }
5130   
5131    // Replacing
5132    //-----------------------------------------------------------------------
5133    /**
5134    * <p>Replaces a String with another String inside a larger String, once.</p>
5135    *
5136    * <p>A {@code null} reference passed to this method is a no-op.</p>
5137    *
5138    * <pre>
5139    * StringUtils.replaceOnce(null, *, *) = null
5140    * StringUtils.replaceOnce("", *, *) = ""
5141    * StringUtils.replaceOnce("any", null, *) = "any"
5142    * StringUtils.replaceOnce("any", *, null) = "any"
5143    * StringUtils.replaceOnce("any", "", *) = "any"
5144    * StringUtils.replaceOnce("aba", "a", null) = "aba"
5145    * StringUtils.replaceOnce("aba", "a", "") = "ba"
5146    * StringUtils.replaceOnce("aba", "a", "z") = "zba"
5147    * </pre>
5148    *
5149    * @see #replace(String text, String searchString, String replacement, int max)
5150    * @param text text to search and replace in, may be null
5151    * @param searchString the String to search for, may be null
5152    * @param replacement the String to replace with, may be null
5153    * @return the text with any replacements processed,
5154    * {@code null} if null String input
5155    */
 
5156  341 toggle public static String replaceOnce(final String text, final String searchString, final String replacement) {
5157  341 return replace(text, searchString, replacement, 1);
5158    }
5159   
5160    /**
5161    * <p>Case insensitively replaces a String with another String inside a larger String, once.</p>
5162    *
5163    * <p>A {@code null} reference passed to this method is a no-op.</p>
5164    *
5165    * <pre>
5166    * StringUtils.replaceOnceIgnoreCase(null, *, *) = null
5167    * StringUtils.replaceOnceIgnoreCase("", *, *) = ""
5168    * StringUtils.replaceOnceIgnoreCase("any", null, *) = "any"
5169    * StringUtils.replaceOnceIgnoreCase("any", *, null) = "any"
5170    * StringUtils.replaceOnceIgnoreCase("any", "", *) = "any"
5171    * StringUtils.replaceOnceIgnoreCase("aba", "a", null) = "aba"
5172    * StringUtils.replaceOnceIgnoreCase("aba", "a", "") = "ba"
5173    * StringUtils.replaceOnceIgnoreCase("aba", "a", "z") = "zba"
5174    * StringUtils.replaceOnceIgnoreCase("FoOFoofoo", "foo", "") = "Foofoo"
5175    * </pre>
5176    *
5177    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5178    * @param text text to search and replace in, may be null
5179    * @param searchString the String to search for (case insensitive), may be null
5180    * @param replacement the String to replace with, may be null
5181    * @return the text with any replacements processed,
5182    * {@code null} if null String input
5183    * @since 3.5
5184    */
 
5185  14 toggle public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) {
5186  14 return replaceIgnoreCase(text, searchString, replacement, 1);
5187    }
5188   
5189    /**
5190    * <p>Replaces each substring of the source String that matches the given regular expression with the given
5191    * replacement using the {@link Pattern#DOTALL} option. DOTALL is also know as single-line mode in Perl.</p>
5192    *
5193    * This call is a {@code null} safe equivalent to:
5194    * <ul>
5195    * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
5196    * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement)}</li>
5197    * </ul>
5198    *
5199    * <p>A {@code null} reference passed to this method is a no-op.</p>
5200    *
5201    * <pre>
5202    * StringUtils.replacePattern(null, *, *) = null
5203    * StringUtils.replacePattern("any", null, *) = "any"
5204    * StringUtils.replacePattern("any", *, null) = "any"
5205    * StringUtils.replacePattern("", "", "zzz") = "zzz"
5206    * StringUtils.replacePattern("", ".*", "zzz") = "zzz"
5207    * StringUtils.replacePattern("", ".+", "zzz") = ""
5208    * StringUtils.replacePattern("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z") = "z"
5209    * StringUtils.replacePattern("ABCabc123", "[a-z]", "_") = "ABC___123"
5210    * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123"
5211    * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "") = "ABC123"
5212    * StringUtils.replacePattern("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit"
5213    * </pre>
5214    *
5215    * @param source
5216    * the source string
5217    * @param regex
5218    * the regular expression to which this string is to be matched
5219    * @param replacement
5220    * the string to be substituted for each match
5221    * @return The resulting {@code String}
5222    * @see #replaceAll(String, String, String)
5223    * @see String#replaceAll(String, String)
5224    * @see Pattern#DOTALL
5225    * @since 3.2
5226    * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5227    */
 
5228  23 toggle public static String replacePattern(final String source, final String regex, final String replacement) {
5229  23 if (source == null || regex == null || replacement == null) {
5230  5 return source;
5231    }
5232  18 return Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(replacement);
5233    }
5234   
5235    /**
5236    * <p>Removes each substring of the source String that matches the given regular expression using the DOTALL option.
5237    * </p>
5238    *
5239    * This call is a {@code null} safe equivalent to:
5240    * <ul>
5241    * <li>{@code source.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
5242    * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(source).replaceAll(StringUtils.EMPTY)}</li>
5243    * </ul>
5244    *
5245    * <p>A {@code null} reference passed to this method is a no-op.</p>
5246    *
5247    * <pre>
5248    * StringUtils.removePattern(null, *) = null
5249    * StringUtils.removePattern("any", null) = "any"
5250    * StringUtils.removePattern("A&lt;__&gt;\n&lt;__&gt;B", "&lt;.*&gt;") = "AB"
5251    * StringUtils.removePattern("ABCabc123", "[a-z]") = "ABC123"
5252    * </pre>
5253    *
5254    * @param source
5255    * the source string
5256    * @param regex
5257    * the regular expression to which this string is to be matched
5258    * @return The resulting {@code String}
5259    * @see #replacePattern(String, String, String)
5260    * @see String#replaceAll(String, String)
5261    * @see Pattern#DOTALL
5262    * @since 3.2
5263    * @since 3.5 Changed {@code null} reference passed to this method is a no-op.
5264    */
 
5265  10 toggle public static String removePattern(final String source, final String regex) {
5266  10 return replacePattern(source, regex, StringUtils.EMPTY);
5267    }
5268   
5269    /**
5270    * <p>Replaces each substring of the text String that matches the given regular expression
5271    * with the given replacement.</p>
5272    *
5273    * This method is a {@code null} safe equivalent to:
5274    * <ul>
5275    * <li>{@code text.replaceAll(regex, replacement)}</li>
5276    * <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
5277    * </ul>
5278    *
5279    * <p>A {@code null} reference passed to this method is a no-op.</p>
5280    *
5281    * <p>Unlike in the {@link #replacePattern(String, String, String)} method, the {@link Pattern#DOTALL} option
5282    * is NOT automatically added.
5283    * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5284    * DOTALL is also know as single-line mode in Perl.</p>
5285    *
5286    * <pre>
5287    * StringUtils.replaceAll(null, *, *) = null
5288    * StringUtils.replaceAll("any", null, *) = "any"
5289    * StringUtils.replaceAll("any", *, null) = "any"
5290    * StringUtils.replaceAll("", "", "zzz") = "zzz"
5291    * StringUtils.replaceAll("", ".*", "zzz") = "zzz"
5292    * StringUtils.replaceAll("", ".+", "zzz") = ""
5293    * StringUtils.replaceAll("abc", "", "ZZ") = "ZZaZZbZZcZZ"
5294    * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z") = "z\nz"
5295    * StringUtils.replaceAll("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z") = "z"
5296    * StringUtils.replaceAll("ABCabc123", "[a-z]", "_") = "ABC___123"
5297    * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_") = "ABC_123"
5298    * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "") = "ABC123"
5299    * StringUtils.replaceAll("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum_dolor_sit"
5300    * </pre>
5301    *
5302    * @param text text to search and replace in, may be null
5303    * @param regex the regular expression to which this string is to be matched
5304    * @param replacement the string to be substituted for each match
5305    * @return the text with any replacements processed,
5306    * {@code null} if null String input
5307    *
5308    * @throws java.util.regex.PatternSyntaxException
5309    * if the regular expression's syntax is invalid
5310    *
5311    * @see #replacePattern(String, String, String)
5312    * @see String#replaceAll(String, String)
5313    * @see java.util.regex.Pattern
5314    * @see java.util.regex.Pattern#DOTALL
5315    * @since 3.5
5316    */
 
5317  24 toggle public static String replaceAll(final String text, final String regex, final String replacement) {
5318  24 if (text == null || regex == null|| replacement == null ) {
5319  5 return text;
5320    }
5321  19 return text.replaceAll(regex, replacement);
5322    }
5323   
5324    /**
5325    * <p>Replaces the first substring of the text string that matches the given regular expression
5326    * with the given replacement.</p>
5327    *
5328    * This method is a {@code null} safe equivalent to:
5329    * <ul>
5330    * <li>{@code text.replaceFirst(regex, replacement)}</li>
5331    * <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
5332    * </ul>
5333    *
5334    * <p>A {@code null} reference passed to this method is a no-op.</p>
5335    *
5336    * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
5337    * To use the DOTALL option prepend <code>"(?s)"</code> to the regex.
5338    * DOTALL is also know as single-line mode in Perl.</p>
5339    *
5340    * <pre>
5341    * StringUtils.replaceFirst(null, *, *) = null
5342    * StringUtils.replaceFirst("any", null, *) = "any"
5343    * StringUtils.replaceFirst("any", *, null) = "any"
5344    * StringUtils.replaceFirst("", "", "zzz") = "zzz"
5345    * StringUtils.replaceFirst("", ".*", "zzz") = "zzz"
5346    * StringUtils.replaceFirst("", ".+", "zzz") = ""
5347    * StringUtils.replaceFirst("abc", "", "ZZ") = "ZZabc"
5348    * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "&lt;.*&gt;", "z") = "z\n&lt;__&gt;"
5349    * StringUtils.replaceFirst("&lt;__&gt;\n&lt;__&gt;", "(?s)&lt;.*&gt;", "z") = "z"
5350    * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_") = "ABC_bc123"
5351    * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_") = "ABC_123abc"
5352    * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "") = "ABC123abc"
5353    * StringUtils.replaceFirst("Lorem ipsum dolor sit", "( +)([a-z]+)", "_$2") = "Lorem_ipsum dolor sit"
5354    * </pre>
5355    *
5356    * @param text text to search and replace in, may be null
5357    * @param regex the regular expression to which this string is to be matched
5358    * @param replacement the string to be substituted for the first match
5359    * @return the text with the first replacement processed,
5360    * {@code null} if null String input
5361    *
5362    * @throws java.util.regex.PatternSyntaxException
5363    * if the regular expression's syntax is invalid
5364    *
5365    * @see String#replaceFirst(String, String)
5366    * @see java.util.regex.Pattern
5367    * @see java.util.regex.Pattern#DOTALL
5368    * @since 3.5
5369    */
 
5370  25 toggle public static String replaceFirst(final String text, final String regex, final String replacement) {
5371  25 if (text == null || regex == null|| replacement == null ) {
5372  5 return text;
5373    }
5374  20 return text.replaceFirst(regex, replacement);
5375    }
5376   
5377    /**
5378    * <p>Replaces all occurrences of a String within another String.</p>
5379    *
5380    * <p>A {@code null} reference passed to this method is a no-op.</p>
5381    *
5382    * <pre>
5383    * StringUtils.replace(null, *, *) = null
5384    * StringUtils.replace("", *, *) = ""
5385    * StringUtils.replace("any", null, *) = "any"
5386    * StringUtils.replace("any", *, null) = "any"
5387    * StringUtils.replace("any", "", *) = "any"
5388    * StringUtils.replace("aba", "a", null) = "aba"
5389    * StringUtils.replace("aba", "a", "") = "b"
5390    * StringUtils.replace("aba", "a", "z") = "zbz"
5391    * </pre>
5392    *
5393    * @see #replace(String text, String searchString, String replacement, int max)
5394    * @param text text to search and replace in, may be null
5395    * @param searchString the String to search for, may be null
5396    * @param replacement the String to replace it with, may be null
5397    * @return the text with any replacements processed,
5398    * {@code null} if null String input
5399    */
 
5400  31 toggle public static String replace(final String text, final String searchString, final String replacement) {
5401  31 return replace(text, searchString, replacement, -1);
5402    }
5403   
5404    /**
5405    * <p>Case insensitively replaces all occurrences of a String within another String.</p>
5406    *
5407    * <p>A {@code null} reference passed to this method is a no-op.</p>
5408    *
5409    * <pre>
5410    * StringUtils.replaceIgnoreCase(null, *, *) = null
5411    * StringUtils.replaceIgnoreCase("", *, *) = ""
5412    * StringUtils.replaceIgnoreCase("any", null, *) = "any"
5413    * StringUtils.replaceIgnoreCase("any", *, null) = "any"
5414    * StringUtils.replaceIgnoreCase("any", "", *) = "any"
5415    * StringUtils.replaceIgnoreCase("aba", "a", null) = "aba"
5416    * StringUtils.replaceIgnoreCase("abA", "A", "") = "b"
5417    * StringUtils.replaceIgnoreCase("aba", "A", "z") = "zbz"
5418    * </pre>
5419    *
5420    * @see #replaceIgnoreCase(String text, String searchString, String replacement, int max)
5421    * @param text text to search and replace in, may be null
5422    * @param searchString the String to search for (case insensitive), may be null
5423    * @param replacement the String to replace it with, may be null
5424    * @return the text with any replacements processed,
5425    * {@code null} if null String input
5426    * @since 3.5
5427    */
 
5428  18 toggle public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) {
5429  18 return replaceIgnoreCase(text, searchString, replacement, -1);
5430    }
5431   
5432    /**
5433    * <p>Replaces a String with another String inside a larger String,
5434    * for the first {@code max} values of the search String.</p>
5435    *
5436    * <p>A {@code null} reference passed to this method is a no-op.</p>
5437    *
5438    * <pre>
5439    * StringUtils.replace(null, *, *, *) = null
5440    * StringUtils.replace("", *, *, *) = ""
5441    * StringUtils.replace("any", null, *, *) = "any"
5442    * StringUtils.replace("any", *, null, *) = "any"
5443    * StringUtils.replace("any", "", *, *) = "any"
5444    * StringUtils.replace("any", *, *, 0) = "any"
5445    * StringUtils.replace("abaa", "a", null, -1) = "abaa"
5446    * StringUtils.replace("abaa", "a", "", -1) = "b"
5447    * StringUtils.replace("abaa", "a", "z", 0) = "abaa"
5448    * StringUtils.replace("abaa", "a", "z", 1) = "zbaa"
5449    * StringUtils.replace("abaa", "a", "z", 2) = "zbza"
5450    * StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
5451    * </pre>
5452    *
5453    * @param text text to search and replace in, may be null
5454    * @param searchString the String to search for, may be null
5455    * @param replacement the String to replace it with, may be null
5456    * @param max maximum number of values to replace, or {@code -1} if no maximum
5457    * @return the text with any replacements processed,
5458    * {@code null} if null String input
5459    */
 
5460  391 toggle public static String replace(final String text, final String searchString, final String replacement, final int max) {
5461  391 return replace(text, searchString, replacement, max, false);
5462    }
5463   
5464    /**
5465    * <p>Replaces a String with another String inside a larger String,
5466    * for the first {@code max} values of the search String,
5467    * case sensitively/insensisitively based on {@code ignoreCase} value.</p>
5468    *
5469    * <p>A {@code null} reference passed to this method is a no-op.</p>
5470    *
5471    * <pre>
5472    * StringUtils.replace(null, *, *, *, false) = null
5473    * StringUtils.replace("", *, *, *, false) = ""
5474    * StringUtils.replace("any", null, *, *, false) = "any"
5475    * StringUtils.replace("any", *, null, *, false) = "any"
5476    * StringUtils.replace("any", "", *, *, false) = "any"
5477    * StringUtils.replace("any", *, *, 0, false) = "any"
5478    * StringUtils.replace("abaa", "a", null, -1, false) = "abaa"
5479    * StringUtils.replace("abaa", "a", "", -1, false) = "b"
5480    * StringUtils.replace("abaa", "a", "z", 0, false) = "abaa"
5481    * StringUtils.replace("abaa", "A", "z", 1, false) = "abaa"
5482    * StringUtils.replace("abaa", "A", "z", 1, true) = "zbaa"
5483    * StringUtils.replace("abAa", "a", "z", 2, true) = "zbza"
5484    * StringUtils.replace("abAa", "a", "z", -1, true) = "zbzz"
5485    * </pre>
5486    *
5487    * @param text text to search and replace in, may be null
5488    * @param searchString the String to search for (case insensitive), may be null
5489    * @param replacement the String to replace it with, may be null
5490    * @param max maximum number of values to replace, or {@code -1} if no maximum
5491    * @param ignoreCase if true replace is case insensitive, otherwise case sensitive
5492    * @return the text with any replacements processed,
5493    * {@code null} if null String input
5494    */
 
5495  452 toggle private static String replace(final String text, String searchString, final String replacement, int max, final boolean ignoreCase) {
5496  452 if (isEmpty(text) || isEmpty(searchString) || replacement == null || max == 0) {
5497  67 return text;
5498    }
5499  385 String searchText = text;
5500  385 if (ignoreCase) {
5501  27 searchText = text.toLowerCase();
5502  27 searchString = searchString.toLowerCase();
5503    }
5504  385 int start = 0;
5505  385 int end = searchText.indexOf(searchString, start);
5506  385 if (end == INDEX_NOT_FOUND) {
5507  284 return text;
5508    }
5509  101 final int replLength = searchString.length();
5510  101 int increase = replacement.length() - replLength;
5511  101 increase = increase < 0 ? 0 : increase;
5512  79 increase *= max < 0 ? 16 : max > 64 ? 64 : max;
5513  101 final StringBuilder buf = new StringBuilder(text.length() + increase);
5514  192 while (end != INDEX_NOT_FOUND) {
5515  167 buf.append(text.substring(start, end)).append(replacement);
5516  167 start = end + replLength;
5517  167 if (--max == 0) {
5518  76 break;
5519    }
5520  91 end = searchText.indexOf(searchString, start);
5521    }
5522  101 buf.append(text.substring(start));
5523  101 return buf.toString();
5524    }
5525   
5526    /**
5527    * <p>Case insensitively replaces a String with another String inside a larger String,
5528    * for the first {@code max} values of the search String.</p>
5529    *
5530    * <p>A {@code null} reference passed to this method is a no-op.</p>
5531    *
5532    * <pre>
5533    * StringUtils.replaceIgnoreCase(null, *, *, *) = null
5534    * StringUtils.replaceIgnoreCase("", *, *, *) = ""
5535    * StringUtils.replaceIgnoreCase("any", null, *, *) = "any"
5536    * StringUtils.replaceIgnoreCase("any", *, null, *) = "any"
5537    * StringUtils.replaceIgnoreCase("any", "", *, *) = "any"
5538    * StringUtils.replaceIgnoreCase("any", *, *, 0) = "any"
5539    * StringUtils.replaceIgnoreCase("abaa", "a", null, -1) = "abaa"
5540    * StringUtils.replaceIgnoreCase("abaa", "a", "", -1) = "b"
5541    * StringUtils.replaceIgnoreCase("abaa", "a", "z", 0) = "abaa"
5542    * StringUtils.replaceIgnoreCase("abaa", "A", "z", 1) = "zbaa"
5543    * StringUtils.replaceIgnoreCase("abAa", "a", "z", 2) = "zbza"
5544    * StringUtils.replaceIgnoreCase("abAa", "a", "z", -1) = "zbzz"
5545    * </pre>
5546    *
5547    * @param text text to search and replace in, may be null
5548    * @param searchString the String to search for (case insensitive), may be null
5549    * @param replacement the String to replace it with, may be null
5550    * @param max maximum number of values to replace, or {@code -1} if no maximum
5551    * @return the text with any replacements processed,
5552    * {@code null} if null String input
5553    * @since 3.5
5554    */
 
5555  61 toggle public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) {
5556  61 return replace(text, searchString, replacement, max, true);
5557    }
5558   
5559    /**
5560    * <p>
5561    * Replaces all occurrences of Strings within another String.
5562    * </p>
5563    *
5564    * <p>
5565    * A {@code null} reference passed to this method is a no-op, or if
5566    * any "search string" or "string to replace" is null, that replace will be
5567    * ignored. This will not repeat. For repeating replaces, call the
5568    * overloaded method.
5569    * </p>
5570    *
5571    * <pre>
5572    * StringUtils.replaceEach(null, *, *) = null
5573    * StringUtils.replaceEach("", *, *) = ""
5574    * StringUtils.replaceEach("aba", null, null) = "aba"
5575    * StringUtils.replaceEach("aba", new String[0], null) = "aba"
5576    * StringUtils.replaceEach("aba", null, new String[0]) = "aba"
5577    * StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
5578    * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
5579    * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
5580    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5581    * (example of how it does not repeat)
5582    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
5583    * </pre>
5584    *
5585    * @param text
5586    * text to search and replace in, no-op if null
5587    * @param searchList
5588    * the Strings to search for, no-op if null
5589    * @param replacementList
5590    * the Strings to replace them with, no-op if null
5591    * @return the text with any replacements processed, {@code null} if
5592    * null String input
5593    * @throws IllegalArgumentException
5594    * if the lengths of the arrays are not the same (null is ok,
5595    * and/or size 0)
5596    * @since 2.4
5597    */
 
5598  15 toggle public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) {
5599  15 return replaceEach(text, searchList, replacementList, false, 0);
5600    }
5601   
5602    /**
5603    * <p>
5604    * Replaces all occurrences of Strings within another String.
5605    * </p>
5606    *
5607    * <p>
5608    * A {@code null} reference passed to this method is a no-op, or if
5609    * any "search string" or "string to replace" is null, that replace will be
5610    * ignored.
5611    * </p>
5612    *
5613    * <pre>
5614    * StringUtils.replaceEachRepeatedly(null, *, *) = null
5615    * StringUtils.replaceEachRepeatedly("", *, *) = ""
5616    * StringUtils.replaceEachRepeatedly("aba", null, null) = "aba"
5617    * StringUtils.replaceEachRepeatedly("aba", new String[0], null) = "aba"
5618    * StringUtils.replaceEachRepeatedly("aba", null, new String[0]) = "aba"
5619    * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, null) = "aba"
5620    * StringUtils.replaceEachRepeatedly("aba", new String[]{"a"}, new String[]{""}) = "b"
5621    * StringUtils.replaceEachRepeatedly("aba", new String[]{null}, new String[]{"a"}) = "aba"
5622    * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
5623    * (example of how it repeats)
5624    * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "tcte"
5625    * StringUtils.replaceEachRepeatedly("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}) = IllegalStateException
5626    * </pre>
5627    *
5628    * @param text
5629    * text to search and replace in, no-op if null
5630    * @param searchList
5631    * the Strings to search for, no-op if null
5632    * @param replacementList
5633    * the Strings to replace them with, no-op if null
5634    * @return the text with any replacements processed, {@code null} if
5635    * null String input
5636    * @throws IllegalStateException
5637    * if the search is repeating and there is an endless loop due
5638    * to outputs of one being inputs to another
5639    * @throws IllegalArgumentException
5640    * if the lengths of the arrays are not the same (null is ok,
5641    * and/or size 0)
5642    * @since 2.4
5643    */
 
5644  11 toggle public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) {
5645    // timeToLive should be 0 if not used or nothing to replace, else it's
5646    // the length of the replace array
5647  11 final int timeToLive = searchList == null ? 0 : searchList.length;
5648  11 return replaceEach(text, searchList, replacementList, true, timeToLive);
5649    }
5650   
5651    /**
5652    * <p>
5653    * Replace all occurrences of Strings within another String.
5654    * This is a private recursive helper method for {@link #replaceEachRepeatedly(String, String[], String[])} and
5655    * {@link #replaceEach(String, String[], String[])}
5656    * </p>
5657    *
5658    * <p>
5659    * A {@code null} reference passed to this method is a no-op, or if
5660    * any "search string" or "string to replace" is null, that replace will be
5661    * ignored.
5662    * </p>
5663    *
5664    * <pre>
5665    * StringUtils.replaceEach(null, *, *, *, *) = null
5666    * StringUtils.replaceEach("", *, *, *, *) = ""
5667    * StringUtils.replaceEach("aba", null, null, *, *) = "aba"
5668    * StringUtils.replaceEach("aba", new String[0], null, *, *) = "aba"
5669    * StringUtils.replaceEach("aba", null, new String[0], *, *) = "aba"
5670    * StringUtils.replaceEach("aba", new String[]{"a"}, null, *, *) = "aba"
5671    * StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *, >=0) = "b"
5672    * StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *, >=0) = "aba"
5673    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *, >=0) = "wcte"
5674    * (example of how it repeats)
5675    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false, >=0) = "dcte"
5676    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true, >=2) = "tcte"
5677    * StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *, *) = IllegalStateException
5678    * </pre>
5679    *
5680    * @param text
5681    * text to search and replace in, no-op if null
5682    * @param searchList
5683    * the Strings to search for, no-op if null
5684    * @param replacementList
5685    * the Strings to replace them with, no-op if null
5686    * @param repeat if true, then replace repeatedly
5687    * until there are no more possible replacements or timeToLive < 0
5688    * @param timeToLive
5689    * if less than 0 then there is a circular reference and endless
5690    * loop
5691    * @return the text with any replacements processed, {@code null} if
5692    * null String input
5693    * @throws IllegalStateException
5694    * if the search is repeating and there is an endless loop due
5695    * to outputs of one being inputs to another
5696    * @throws IllegalArgumentException
5697    * if the lengths of the arrays are not the same (null is ok,
5698    * and/or size 0)
5699    * @since 2.4
5700    */
 
5701  33 toggle private static String replaceEach(
5702    final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) {
5703   
5704    // mchyzer Performance note: This creates very few new objects (one major goal)
5705    // let me know if there are performance requests, we can create a harness to measure
5706   
5707  33 if (text == null || text.isEmpty() || searchList == null ||
5708    searchList.length == 0 || replacementList == null || replacementList.length == 0) {
5709  12 return text;
5710    }
5711   
5712    // if recursing, this shouldn't be less than 0
5713  21 if (timeToLive < 0) {
5714  1 throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
5715    "output of one loop is the input of another");
5716    }
5717   
5718  20 final int searchLength = searchList.length;
5719  20 final int replacementLength = replacementList.length;
5720   
5721    // make sure lengths are ok, these need to be equal
5722  20 if (searchLength != replacementLength) {
5723  1 throw new IllegalArgumentException("Search and Replace array lengths don't match: "
5724    + searchLength
5725    + " vs "
5726    + replacementLength);
5727    }
5728   
5729    // keep track of which still have matches
5730  19 final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
5731   
5732    // index on index that the match was found
5733  19 int textIndex = -1;
5734  19 int replaceIndex = -1;
5735  19 int tempIndex = -1;
5736   
5737    // index of replace array that will replace the search string found
5738    // NOTE: logic duplicated below START
5739  110 for (int i = 0; i < searchLength; i++) {
5740  91 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5741    searchList[i].isEmpty() || replacementList[i] == null) {
5742  4 continue;
5743    }
5744  87 tempIndex = text.indexOf(searchList[i]);
5745   
5746    // see if we need to keep searching for this
5747  87 if (tempIndex == -1) {
5748  59 noMoreMatchesForReplIndex[i] = true;
5749    } else {
5750  28 if (textIndex == -1 || tempIndex < textIndex) {
5751  14 textIndex = tempIndex;
5752  14 replaceIndex = i;
5753    }
5754    }
5755    }
5756    // NOTE: logic mostly below END
5757   
5758    // no search strings found, we are done
5759  19 if (textIndex == -1) {
5760  6 return text;
5761    }
5762   
5763  13 int start = 0;
5764   
5765    // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
5766  13 int increase = 0;
5767   
5768    // count the replacement text elements that are larger than their corresponding text being replaced
5769  96 for (int i = 0; i < searchList.length; i++) {
5770  83 if (searchList[i] == null || replacementList[i] == null) {
5771  1 continue;
5772    }
5773  82 final int greater = replacementList[i].length() - searchList[i].length();
5774  82 if (greater > 0) {
5775  3 increase += 3 * greater; // assume 3 matches
5776    }
5777    }
5778    // have upper-bound at 20% increase, then let Java take over
5779  13 increase = Math.min(increase, text.length() / 5);
5780   
5781  13 final StringBuilder buf = new StringBuilder(text.length() + increase);
5782   
5783  46 while (textIndex != -1) {
5784   
5785  45 for (int i = start; i < textIndex; i++) {
5786  12 buf.append(text.charAt(i));
5787    }
5788  33 buf.append(replacementList[replaceIndex]);
5789   
5790  33 start = textIndex + searchList[replaceIndex].length();
5791   
5792  33 textIndex = -1;
5793  33 replaceIndex = -1;
5794  33 tempIndex = -1;
5795    // find the next earliest match
5796    // NOTE: logic mostly duplicated above START
5797  685 for (int i = 0; i < searchLength; i++) {
5798  652 if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
5799    searchList[i].isEmpty() || replacementList[i] == null) {
5800  571 continue;
5801    }
5802  81 tempIndex = text.indexOf(searchList[i], start);
5803   
5804    // see if we need to keep searching for this
5805  81 if (tempIndex == -1) {
5806  28 noMoreMatchesForReplIndex[i] = true;
5807    } else {
5808  53 if (textIndex == -1 || tempIndex < textIndex) {
5809  34 textIndex = tempIndex;
5810  34 replaceIndex = i;
5811    }
5812    }
5813    }
5814    // NOTE: logic duplicated above END
5815   
5816    }
5817  13 final int textLength = text.length();
5818  24 for (int i = start; i < textLength; i++) {
5819  11 buf.append(text.charAt(i));
5820    }
5821  13 final String result = buf.toString();
5822  13 if (!repeat) {
5823  6 return result;
5824    }
5825   
5826  7 return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
5827    }
5828   
5829    // Replace, character based
5830    //-----------------------------------------------------------------------
5831    /**
5832    * <p>Replaces all occurrences of a character in a String with another.
5833    * This is a null-safe version of {@link String#replace(char, char)}.</p>
5834    *
5835    * <p>A {@code null} string input returns {@code null}.
5836    * An empty ("") string input returns an empty string.</p>
5837    *
5838    * <pre>
5839    * StringUtils.replaceChars(null, *, *) = null
5840    * StringUtils.replaceChars("", *, *) = ""
5841    * StringUtils.replaceChars("abcba", 'b', 'y') = "aycya"
5842    * StringUtils.replaceChars("abcba", 'z', 'y') = "abcba"
5843    * </pre>
5844    *
5845    * @param str String to replace characters in, may be null
5846    * @param searchChar the character to search for, may be null
5847    * @param replaceChar the character to replace, may be null
5848    * @return modified String, {@code null} if null string input
5849    * @since 2.0
5850    */
 
5851  6 toggle public static String replaceChars(final String str, final char searchChar, final char replaceChar) {
5852  6 if (str == null) {
5853  1 return null;
5854    }
5855  5 return str.replace(searchChar, replaceChar);
5856    }
5857   
5858    /**
5859    * <p>Replaces multiple characters in a String in one go.
5860    * This method can also be used to delete characters.</p>
5861    *
5862    * <p>For example:<br>
5863    * <code>replaceChars(&quot;hello&quot;, &quot;ho&quot;, &quot;jy&quot;) = jelly</code>.</p>
5864    *
5865    * <p>A {@code null} string input returns {@code null}.
5866    * An empty ("") string input returns an empty string.
5867    * A null or empty set of search characters returns the input string.</p>
5868    *
5869    * <p>The length of the search characters should normally equal the length
5870    * of the replace characters.
5871    * If the search characters is longer, then the extra search characters
5872    * are deleted.
5873    * If the search characters is shorter, then the extra replace characters
5874    * are ignored.</p>
5875    *
5876    * <pre>
5877    * StringUtils.replaceChars(null, *, *) = null
5878    * StringUtils.replaceChars("", *, *) = ""
5879    * StringUtils.replaceChars("abc", null, *) = "abc"
5880    * StringUtils.replaceChars("abc", "", *) = "abc"
5881    * StringUtils.replaceChars("abc", "b", null) = "ac"
5882    * StringUtils.replaceChars("abc", "b", "") = "ac"
5883    * StringUtils.replaceChars("abcba", "bc", "yz") = "ayzya"
5884    * StringUtils.replaceChars("abcba", "bc", "y") = "ayya"
5885    * StringUtils.replaceChars("abcba", "bc", "yzx") = "ayzya"
5886    * </pre>
5887    *
5888    * @param str String to replace characters in, may be null
5889    * @param searchChars a set of characters to search for, may be null
5890    * @param replaceChars a set of characters to replace, may be null
5891    * @return modified String, {@code null} if null string input
5892    * @since 2.0
5893    */
 
5894  30 toggle public static String replaceChars(final String str, final String searchChars, String replaceChars) {
5895  30 if (isEmpty(str) || isEmpty(searchChars)) {
5896  16 return str;
5897    }
5898  14 if (replaceChars == null) {
5899  1 replaceChars = EMPTY;
5900    }
5901  14 boolean modified = false;
5902  14 final int replaceCharsLength = replaceChars.length();
5903  14 final int strLength = str.length();
5904  14 final StringBuilder buf = new StringBuilder(strLength);
5905  83 for (int i = 0; i < strLength; i++) {
5906  69 final char ch = str.charAt(i);
5907  69 final int index = searchChars.indexOf(ch);
5908  69 if (index >= 0) {
5909  35 modified = true;
5910  35 if (index < replaceCharsLength) {
5911  31 buf.append(replaceChars.charAt(index));
5912    }
5913    } else {
5914  34 buf.append(ch);
5915    }
5916    }
5917  14 if (modified) {
5918  12 return buf.toString();
5919    }
5920  2 return str;
5921    }
5922   
5923    // Overlay
5924    //-----------------------------------------------------------------------
5925    /**
5926    * <p>Overlays part of a String with another String.</p>
5927    *
5928    * <p>A {@code null} string input returns {@code null}.
5929    * A negative index is treated as zero.
5930    * An index greater than the string length is treated as the string length.
5931    * The start index is always the smaller of the two indices.</p>
5932    *
5933    * <pre>
5934    * StringUtils.overlay(null, *, *, *) = null
5935    * StringUtils.overlay("", "abc", 0, 0) = "abc"
5936    * StringUtils.overlay("abcdef", null, 2, 4) = "abef"
5937    * StringUtils.overlay("abcdef", "", 2, 4) = "abef"
5938    * StringUtils.overlay("abcdef", "", 4, 2) = "abef"
5939    * StringUtils.overlay("abcdef", "zzzz", 2, 4) = "abzzzzef"
5940    * StringUtils.overlay("abcdef", "zzzz", 4, 2) = "abzzzzef"
5941    * StringUtils.overlay("abcdef", "zzzz", -1, 4) = "zzzzef"
5942    * StringUtils.overlay("abcdef", "zzzz", 2, 8) = "abzzzz"
5943    * StringUtils.overlay("abcdef", "zzzz", -2, -3) = "zzzzabcdef"
5944    * StringUtils.overlay("abcdef", "zzzz", 8, 10) = "abcdefzzzz"
5945    * </pre>
5946    *
5947    * @param str the String to do overlaying in, may be null
5948    * @param overlay the String to overlay, may be null
5949    * @param start the position to start overlaying at
5950    * @param end the position to stop overlaying before
5951    * @return overlayed String, {@code null} if null String input
5952    * @since 2.0
5953    */
 
5954  21 toggle public static String overlay(final String str, String overlay, int start, int end) {
5955  21 if (str == null) {
5956  2 return null;
5957    }
5958  19 if (overlay == null) {
5959  3 overlay = EMPTY;
5960    }
5961  19 final int len = str.length();
5962  19 if (start < 0) {
5963  4 start = 0;
5964    }
5965  19 if (start > len) {
5966  4 start = len;
5967    }
5968  19 if (end < 0) {
5969  4 end = 0;
5970    }
5971  19 if (end > len) {
5972  4 end = len;
5973    }
5974  19 if (start > end) {
5975  5 final int temp = start;
5976  5 start = end;
5977  5 end = temp;
5978    }
5979  19 return new StringBuilder(len + start - end + overlay.length() + 1)
5980    .append(str.substring(0, start))
5981    .append(overlay)
5982    .append(str.substring(end))
5983    .toString();
5984    }
5985   
5986    // Chomping
5987    //-----------------------------------------------------------------------
5988    /**
5989    * <p>Removes one newline from end of a String if it's there,
5990    * otherwise leave it alone. A newline is &quot;{@code \n}&quot;,
5991    * &quot;{@code \r}&quot;, or &quot;{@code \r\n}&quot;.</p>
5992    *
5993    * <p>NOTE: This method changed in 2.0.
5994    * It now more closely matches Perl chomp.</p>
5995    *
5996    * <pre>
5997    * StringUtils.chomp(null) = null
5998    * StringUtils.chomp("") = ""
5999    * StringUtils.chomp("abc \r") = "abc "
6000    * StringUtils.chomp("abc\n") = "abc"
6001    * StringUtils.chomp("abc\r\n") = "abc"
6002    * StringUtils.chomp("abc\r\n\r\n") = "abc\r\n"
6003    * StringUtils.chomp("abc\n\r") = "abc\n"
6004    * StringUtils.chomp("abc\n\rabc") = "abc\n\rabc"
6005    * StringUtils.chomp("\r") = ""
6006    * StringUtils.chomp("\n") = ""
6007    * StringUtils.chomp("\r\n") = ""
6008    * </pre>
6009    *
6010    * @param str the String to chomp a newline from, may be null
6011    * @return String without newline, {@code null} if null String input
6012    */
 
6013  16 toggle public static String chomp(final String str) {
6014  16 if (isEmpty(str)) {
6015  2 return str;
6016    }
6017   
6018  14 if (str.length() == 1) {
6019  3 final char ch = str.charAt(0);
6020  3 if (ch == CharUtils.CR || ch == CharUtils.LF) {
6021  2 return EMPTY;
6022    }
6023  1 return str;
6024    }
6025   
6026  11 int lastIdx = str.length() - 1;
6027  11 final char last = str.charAt(lastIdx);
6028   
6029  11 if (last == CharUtils.LF) {
6030  5 if (str.charAt(lastIdx - 1) == CharUtils.CR) {
6031  3 lastIdx--;
6032    }
6033  6 } else if (last != CharUtils.CR) {
6034  3 lastIdx++;
6035    }
6036  11 return str.substring(0, lastIdx);
6037    }
6038   
6039    /**
6040    * <p>Removes {@code separator} from the end of
6041    * {@code str} if it's there, otherwise leave it alone.</p>
6042    *
6043    * <p>NOTE: This method changed in version 2.0.
6044    * It now more closely matches Perl chomp.
6045    * For the previous behavior, use {@link #substringBeforeLast(String, String)}.
6046    * This method uses {@link String#endsWith(String)}.</p>
6047    *
6048    * <pre>
6049    * StringUtils.chomp(null, *) = null
6050    * StringUtils.chomp("", *) = ""
6051    * StringUtils.chomp("foobar", "bar") = "foo"
6052    * StringUtils.chomp("foobar", "baz") = "foobar"
6053    * StringUtils.chomp("foo", "foo") = ""
6054    * StringUtils.chomp("foo ", "foo") = "foo "
6055    * StringUtils.chomp(" foo", "foo") = " "
6056    * StringUtils.chomp("foo", "foooo") = "foo"
6057    * StringUtils.chomp("foo", "") = "foo"
6058    * StringUtils.chomp("foo", null) = "foo"
6059    * </pre>
6060    *
6061    * @param str the String to chomp from, may be null
6062    * @param separator separator String, may be null
6063    * @return String without trailing separator, {@code null} if null String input
6064    * @deprecated This feature will be removed in Lang 4.0, use {@link StringUtils#removeEnd(String, String)} instead
6065    */
 
6066  14 toggle @Deprecated
6067    public static String chomp(final String str, final String separator) {
6068  14 return removeEnd(str,separator);
6069    }
6070   
6071    // Chopping
6072    //-----------------------------------------------------------------------
6073    /**
6074    * <p>Remove the last character from a String.</p>
6075    *
6076    * <p>If the String ends in {@code \r\n}, then remove both
6077    * of them.</p>
6078    *
6079    * <pre>
6080    * StringUtils.chop(null) = null
6081    * StringUtils.chop("") = ""
6082    * StringUtils.chop("abc \r") = "abc "
6083    * StringUtils.chop("abc\n") = "abc"
6084    * StringUtils.chop("abc\r\n") = "abc"
6085    * StringUtils.chop("abc") = "ab"
6086    * StringUtils.chop("abc\nabc") = "abc\nab"
6087    * StringUtils.chop("a") = ""
6088    * StringUtils.chop("\r") = ""
6089    * StringUtils.chop("\n") = ""
6090    * StringUtils.chop("\r\n") = ""
6091    * </pre>
6092    *
6093    * @param str the String to chop last character from, may be null
6094    * @return String without last character, {@code null} if null String input
6095    */
 
6096  12 toggle public static String chop(final String str) {
6097  12 if (str == null) {
6098  1 return null;
6099    }
6100  11 final int strLen = str.length();
6101  11 if (strLen < 2) {
6102  4 return EMPTY;
6103    }
6104  7 final int lastIdx = strLen - 1;
6105  7 final String ret = str.substring(0, lastIdx);
6106  7 final char last = str.charAt(lastIdx);
6107  7 if (last == CharUtils.LF && ret.charAt(lastIdx - 1) == CharUtils.CR) {
6108  2 return ret.substring(0, lastIdx - 1);
6109    }
6110  5 return ret;
6111    }
6112   
6113    // Conversion
6114    //-----------------------------------------------------------------------
6115   
6116    // Padding
6117    //-----------------------------------------------------------------------
6118    /**
6119    * <p>Repeat a String {@code repeat} times to form a
6120    * new String.</p>
6121    *
6122    * <pre>
6123    * StringUtils.repeat(null, 2) = null
6124    * StringUtils.repeat("", 0) = ""
6125    * StringUtils.repeat("", 2) = ""
6126    * StringUtils.repeat("a", 3) = "aaa"
6127    * StringUtils.repeat("ab", 2) = "abab"
6128    * StringUtils.repeat("a", -2) = ""
6129    * </pre>
6130    *
6131    * @param str the String to repeat, may be null
6132    * @param repeat number of times to repeat str, negative treated as zero
6133    * @return a new String consisting of the original String repeated,
6134    * {@code null} if null String input
6135    */
 
6136  16 toggle public static String repeat(final String str, final int repeat) {
6137    // Performance tuned for 2.0 (JDK1.4)
6138   
6139  16 if (str == null) {
6140  3 return null;
6141    }
6142  13 if (repeat <= 0) {
6143  3 return EMPTY;
6144    }
6145  10 final int inputLength = str.length();
6146  10 if (repeat == 1 || inputLength == 0) {
6147  3 return str;
6148    }
6149  7 if (inputLength == 1 && repeat <= PAD_LIMIT) {
6150  2 return repeat(str.charAt(0), repeat);
6151    }
6152   
6153  5 final int outputLength = inputLength * repeat;
6154  5 switch (inputLength) {
6155  2 case 1 :
6156  2 return repeat(str.charAt(0), repeat);
6157  1 case 2 :
6158  1 final char ch0 = str.charAt(0);
6159  1 final char ch1 = str.charAt(1);
6160  1 final char[] output2 = new char[outputLength];
6161  4 for (int i = repeat * 2 - 2; i >= 0; i--, i--) {
6162  3 output2[i] = ch0;
6163  3 output2[i + 1] = ch1;
6164    }
6165  1 return new String(output2);
6166  2 default :
6167  2 final StringBuilder buf = new StringBuilder(outputLength);
6168  8 for (int i = 0; i < repeat; i++) {
6169  6 buf.append(str);
6170    }
6171  2 return buf.toString();
6172    }
6173    }
6174   
6175    /**
6176    * <p>Repeat a String {@code repeat} times to form a
6177    * new String, with a String separator injected each time. </p>
6178    *
6179    * <pre>
6180    * StringUtils.repeat(null, null, 2) = null
6181    * StringUtils.repeat(null, "x", 2) = null
6182    * StringUtils.repeat("", null, 0) = ""
6183    * StringUtils.repeat("", "", 2) = ""
6184    * StringUtils.repeat("", "x", 3) = "xxx"
6185    * StringUtils.repeat("?", ", ", 3) = "?, ?, ?"
6186    * </pre>
6187    *
6188    * @param str the String to repeat, may be null
6189    * @param separator the String to inject, may be null
6190    * @param repeat number of times to repeat str, negative treated as zero
6191    * @return a new String consisting of the original String repeated,
6192    * {@code null} if null String input
6193    * @since 2.5
6194    */
 
6195  7 toggle public static String repeat(final String str, final String separator, final int repeat) {
6196  7 if(str == null || separator == null) {
6197  3 return repeat(str, repeat);
6198    }
6199    // given that repeat(String, int) is quite optimized, better to rely on it than try and splice this into it
6200  4 final String result = repeat(str + separator, repeat);
6201  4 return removeEnd(result, separator);
6202    }
6203   
6204    /**
6205    * <p>Returns padding using the specified delimiter repeated
6206    * to a given length.</p>
6207    *
6208    * <pre>
6209    * StringUtils.repeat('e', 0) = ""
6210    * StringUtils.repeat('e', 3) = "eee"
6211    * StringUtils.repeat('e', -2) = ""
6212    * </pre>
6213    *
6214    * <p>Note: this method doesn't not support padding with
6215    * <a href="http://www.unicode.org/glossary/#supplementary_character">Unicode Supplementary Characters</a>
6216    * as they require a pair of {@code char}s to be represented.
6217    * If you are needing to support full I18N of your applications
6218    * consider using {@link #repeat(String, int)} instead.
6219    * </p>
6220    *
6221    * @param ch character to repeat
6222    * @param repeat number of times to repeat char, negative treated as zero
6223    * @return String with repeated character
6224    * @see #repeat(String, int)
6225    */
 
6226  129 toggle public static String repeat(final char ch, final int repeat) {
6227  129 if (repeat <= 0) {
6228  2 return EMPTY;
6229    }
6230  127 final char[] buf = new char[repeat];
6231  20340 for (int i = repeat - 1; i >= 0; i--) {
6232  20213 buf[i] = ch;
6233    }
6234  127 return new String(buf);
6235    }
6236   
6237    /**
6238    * <p>Right pad a String with spaces (' ').</p>
6239    *
6240    * <p>The String is padded to the size of {@code size}.</p>
6241    *
6242    * <pre>
6243    * StringUtils.rightPad(null, *) = null
6244    * StringUtils.rightPad("", 3) = " "
6245    * StringUtils.rightPad("bat", 3) = "bat"
6246    * StringUtils.rightPad("bat", 5) = "bat "
6247    * StringUtils.rightPad("bat", 1) = "bat"
6248    * StringUtils.rightPad("bat", -1) = "bat"
6249    * </pre>
6250    *
6251    * @param str the String to pad out, may be null
6252    * @param size the size to pad to
6253    * @return right padded String or original String if no padding is necessary,
6254    * {@code null} if null String input
6255    */
 
6256  5 toggle public static String rightPad(final String str, final int size) {
6257  5 return rightPad(str, size, ' ');
6258    }
6259   
6260    /**
6261    * <p>Right pad a String with a specified character.</p>
6262    *
6263    * <p>The String is padded to the size of {@code size}.</p>
6264    *
6265    * <pre>
6266    * StringUtils.rightPad(null, *, *) = null
6267    * StringUtils.rightPad("", 3, 'z') = "zzz"
6268    * StringUtils.rightPad("bat", 3, 'z') = "bat"
6269    * StringUtils.rightPad("bat", 5, 'z') = "batzz"
6270    * StringUtils.rightPad("bat", 1, 'z') = "bat"
6271    * StringUtils.rightPad("bat", -1, 'z') = "bat"
6272    * </pre>
6273    *
6274    * @param str the String to pad out, may be null
6275    * @param size the size to pad to
6276    * @param padChar the character to pad with
6277    * @return right padded String or original String if no padding is necessary,
6278    * {@code null} if null String input
6279    * @since 2.0
6280    */
 
6281  32 toggle public static String rightPad(final String str, final int size, final char padChar) {
6282  32 if (str == null) {
6283  2 return null;
6284    }
6285  30 final int pads = size - str.length();
6286  30 if (pads <= 0) {
6287  4 return str; // returns original String when possible
6288    }
6289  26 if (pads > PAD_LIMIT) {
6290  1 return rightPad(str, size, String.valueOf(padChar));
6291    }
6292  25 return str.concat(repeat(padChar, pads));
6293    }
6294   
6295    /**
6296    * <p>Right pad a String with a specified String.</p>
6297    *
6298    * <p>The String is padded to the size of {@code size}.</p>
6299    *
6300    * <pre>
6301    * StringUtils.rightPad(null, *, *) = null
6302    * StringUtils.rightPad("", 3, "z") = "zzz"
6303    * StringUtils.rightPad("bat", 3, "yz") = "bat"
6304    * StringUtils.rightPad("bat", 5, "yz") = "batyz"
6305    * StringUtils.rightPad("bat", 8, "yz") = "batyzyzy"
6306    * StringUtils.rightPad("bat", 1, "yz") = "bat"
6307    * StringUtils.rightPad("bat", -1, "yz") = "bat"
6308    * StringUtils.rightPad("bat", 5, null) = "bat "
6309    * StringUtils.rightPad("bat", 5, "") = "bat "
6310    * </pre>
6311    *
6312    * @param str the String to pad out, may be null
6313    * @param size the size to pad to
6314    * @param padStr the String to pad with, null or empty treated as single space
6315    * @return right padded String or original String if no padding is necessary,
6316    * {@code null} if null String input
6317    */
 
6318  19 toggle public static String rightPad(final String str, final int size, String padStr) {
6319  19 if (str == null) {
6320  2 return null;
6321    }
6322  17 if (isEmpty(padStr)) {
6323  2 padStr = SPACE;
6324    }
6325  17 final int padLen = padStr.length();
6326  17 final int strLen = str.length();
6327  17 final int pads = size - strLen;
6328  17 if (pads <= 0) {
6329  2 return str; // returns original String when possible
6330    }
6331  15 if (padLen == 1 && pads <= PAD_LIMIT) {
6332  9 return rightPad(str, size, padStr.charAt(0));
6333    }
6334   
6335  6 if (pads == padLen) {
6336  2 return str.concat(padStr);
6337  4 } else if (pads < padLen) {
6338  1 return str.concat(padStr.substring(0, pads));
6339    } else {
6340  3 final char[] padding = new char[pads];
6341  3 final char[] padChars = padStr.toCharArray();
6342  10007 for (int i = 0; i < pads; i++) {
6343  10004 padding[i] = padChars[i % padLen];
6344    }
6345  3 return str.concat(new String(padding));
6346    }
6347    }
6348   
6349    /**
6350    * <p>Left pad a String with spaces (' ').</p>
6351    *
6352    * <p>The String is padded to the size of {@code size}.</p>
6353    *
6354    * <pre>
6355    * StringUtils.leftPad(null, *) = null
6356    * StringUtils.leftPad("", 3) = " "
6357    * StringUtils.leftPad("bat", 3) = "bat"
6358    * StringUtils.leftPad("bat", 5) = " bat"
6359    * StringUtils.leftPad("bat", 1) = "bat"
6360    * StringUtils.leftPad("bat", -1) = "bat"
6361    * </pre>
6362    *
6363    * @param str the String to pad out, may be null
6364    * @param size the size to pad to
6365    * @return left padded String or original String if no padding is necessary,
6366    * {@code null} if null String input
6367    */
 
6368  4 toggle public static String leftPad(final String str, final int size) {
6369  4 return leftPad(str, size, ' ');
6370    }
6371   
6372    /**
6373    * <p>Left pad a String with a specified character.</p>
6374    *
6375    * <p>Pad to a size of {@code size}.</p>
6376    *
6377    * <pre>
6378    * StringUtils.leftPad(null, *, *) = null
6379    * StringUtils.leftPad("", 3, 'z') = "zzz"
6380    * StringUtils.leftPad("bat", 3, 'z') = "bat"
6381    * StringUtils.leftPad("bat", 5, 'z') = "zzbat"
6382    * StringUtils.leftPad("bat", 1, 'z') = "bat"
6383    * StringUtils.leftPad("bat", -1, 'z') = "bat"
6384    * </pre>
6385    *
6386    * @param str the String to pad out, may be null
6387    * @param size the size to pad to
6388    * @param padChar the character to pad with
6389    * @return left padded String or original String if no padding is necessary,
6390    * {@code null} if null String input
6391    * @since 2.0
6392    */
 
6393  268457 toggle public static String leftPad(final String str, final int size, final char padChar) {
6394  268457 if (str == null) {
6395  2 return null;
6396    }
6397  268455 final int pads = size - str.length();
6398  268455 if (pads <= 0) {
6399  268357 return str; // returns original String when possible
6400    }
6401  98 if (pads > PAD_LIMIT) {
6402  1 return leftPad(str, size, String.valueOf(padChar));
6403    }
6404  97 return repeat(padChar, pads).concat(str);
6405    }
6406   
6407    /**
6408    * <p>Left pad a String with a specified String.</p>
6409    *
6410    * <p>Pad to a size of {@code size}.</p>
6411    *
6412    * <pre>
6413    * StringUtils.leftPad(null, *, *) = null
6414    * StringUtils.leftPad("", 3, "z") = "zzz"
6415    * StringUtils.leftPad("bat", 3, "yz") = "bat"
6416    * StringUtils.leftPad("bat", 5, "yz") = "yzbat"
6417    * StringUtils.leftPad("bat", 8, "yz") = "yzyzybat"
6418    * StringUtils.leftPad("bat", 1, "yz") = "bat"
6419    * StringUtils.leftPad("bat", -1, "yz") = "bat"
6420    * StringUtils.leftPad("bat", 5, null) = " bat"
6421    * StringUtils.leftPad("bat", 5, "") = " bat"
6422    * </pre>
6423    *
6424    * @param str the String to pad out, may be null
6425    * @param size the size to pad to
6426    * @param padStr the String to pad with, null or empty treated as single space
6427    * @return left padded String or original String if no padding is necessary,
6428    * {@code null} if null String input
6429    */
 
6430  19 toggle public static String leftPad(final String str, final int size, String padStr) {
6431  19 if (str == null) {
6432  2 return null;
6433    }
6434  17 if (isEmpty(padStr)) {
6435  2 padStr = SPACE;
6436    }
6437  17 final int padLen = padStr.length();
6438  17 final int strLen = str.length();
6439  17 final int pads = size - strLen;
6440  17 if (pads <= 0) {
6441  2 return str; // returns original String when possible
6442    }
6443  15 if (padLen == 1 && pads <= PAD_LIMIT) {
6444  9 return leftPad(str, size, padStr.charAt(0));
6445    }
6446   
6447  6 if (pads == padLen) {
6448  1 return padStr.concat(str);
6449  5 } else if (pads < padLen) {
6450  2 return padStr.substring(0, pads).concat(str);
6451    } else {
6452  3 final char[] padding = new char[pads];
6453  3 final char[] padChars = padStr.toCharArray();
6454  10007 for (int i = 0; i < pads; i++) {
6455  10004 padding[i] = padChars[i % padLen];
6456    }
6457  3 return new String(padding).concat(str);
6458    }
6459    }
6460   
6461    /**
6462    * Gets a CharSequence length or {@code 0} if the CharSequence is
6463    * {@code null}.
6464    *
6465    * @param cs
6466    * a CharSequence or {@code null}
6467    * @return CharSequence length or {@code 0} if the CharSequence is
6468    * {@code null}.
6469    * @since 2.4
6470    * @since 3.0 Changed signature from length(String) to length(CharSequence)
6471    */
 
6472  20 toggle public static int length(final CharSequence cs) {
6473  20 return cs == null ? 0 : cs.length();
6474    }
6475   
6476    // Centering
6477    //-----------------------------------------------------------------------
6478    /**
6479    * <p>Centers a String in a larger String of size {@code size}
6480    * using the space character (' ').</p>
6481    *
6482    * <p>If the size is less than the String length, the String is returned.
6483    * A {@code null} String returns {@code null}.
6484    * A negative size is treated as zero.</p>
6485    *
6486    * <p>Equivalent to {@code center(str, size, " ")}.</p>
6487    *
6488    * <pre>
6489    * StringUtils.center(null, *) = null
6490    * StringUtils.center("", 4) = " "
6491    * StringUtils.center("ab", -1) = "ab"
6492    * StringUtils.center("ab", 4) = " ab "
6493    * StringUtils.center("abcd", 2) = "abcd"
6494    * StringUtils.center("a", 4) = " a "
6495    * </pre>
6496    *
6497    * @param str the String to center, may be null
6498    * @param size the int size of new String, negative treated as zero
6499    * @return centered String, {@code null} if null String input
6500    */
 
6501  11 toggle public static String center(final String str, final int size) {
6502  11 return center(str, size, ' ');
6503    }
6504   
6505    /**
6506    * <p>Centers a String in a larger String of size {@code size}.
6507    * Uses a supplied character as the value to pad the String with.</p>
6508    *
6509    * <p>If the size is less than the String length, the String is returned.
6510    * A {@code null} String returns {@code null}.
6511    * A negative size is treated as zero.</p>
6512    *
6513    * <pre>
6514    * StringUtils.center(null, *, *) = null
6515    * StringUtils.center("", 4, ' ') = " "
6516    * StringUtils.center("ab", -1, ' ') = "ab"
6517    * StringUtils.center("ab", 4, ' ') = " ab "
6518    * StringUtils.center("abcd", 2, ' ') = "abcd"
6519    * StringUtils.center("a", 4, ' ') = " a "
6520    * StringUtils.center("a", 4, 'y') = "yayy"
6521    * </pre>
6522    *
6523    * @param str the String to center, may be null
6524    * @param size the int size of new String, negative treated as zero
6525    * @param padChar the character to pad the new String with
6526    * @return centered String, {@code null} if null String input
6527    * @since 2.0
6528    */
 
6529  23 toggle public static String center(String str, final int size, final char padChar) {
6530  23 if (str == null || size <= 0) {
6531  8 return str;
6532    }
6533  15 final int strLen = str.length();
6534  15 final int pads = size - strLen;
6535  15 if (pads <= 0) {
6536  4 return str;
6537    }
6538  11 str = leftPad(str, strLen + pads / 2, padChar);
6539  11 str = rightPad(str, size, padChar);
6540  11 return str;
6541    }
6542   
6543    /**
6544    * <p>Centers a String in a larger String of size {@code size}.
6545    * Uses a supplied String as the value to pad the String with.</p>
6546    *
6547    * <p>If the size is less than the String length, the String is returned.
6548    * A {@code null} String returns {@code null}.
6549    * A negative size is treated as zero.</p>
6550    *
6551    * <pre>
6552    * StringUtils.center(null, *, *) = null
6553    * StringUtils.center("", 4, " ") = " "
6554    * StringUtils.center("ab", -1, " ") = "ab"
6555    * StringUtils.center("ab", 4, " ") = " ab "
6556    * StringUtils.center("abcd", 2, " ") = "abcd"
6557    * StringUtils.center("a", 4, " ") = " a "
6558    * StringUtils.center("a", 4, "yz") = "yayz"
6559    * StringUtils.center("abc", 7, null) = " abc "
6560    * StringUtils.center("abc", 7, "") = " abc "
6561    * </pre>
6562    *
6563    * @param str the String to center, may be null
6564    * @param size the int size of new String, negative treated as zero
6565    * @param padStr the String to pad the new String with, must not be null or empty
6566    * @return centered String, {@code null} if null String input
6567    * @throws IllegalArgumentException if padStr is {@code null} or empty
6568    */
 
6569  15 toggle public static String center(String str, final int size, String padStr) {
6570  15 if (str == null || size <= 0) {
6571  5 return str;
6572    }
6573  10 if (isEmpty(padStr)) {
6574  2 padStr = SPACE;
6575    }
6576  10 final int strLen = str.length();
6577  10 final int pads = size - strLen;
6578  10 if (pads <= 0) {
6579  2 return str;
6580    }
6581  8 str = leftPad(str, strLen + pads / 2, padStr);
6582  8 str = rightPad(str, size, padStr);
6583  8 return str;
6584    }
6585   
6586    // Case conversion
6587    //-----------------------------------------------------------------------
6588    /**
6589    * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
6590    *
6591    * <p>A {@code null} input String returns {@code null}.</p>
6592    *
6593    * <pre>
6594    * StringUtils.upperCase(null) = null
6595    * StringUtils.upperCase("") = ""
6596    * StringUtils.upperCase("aBc") = "ABC"
6597    * </pre>
6598    *
6599    * <p><strong>Note:</strong> As described in the documentation for {@link String#toUpperCase()},
6600    * the result of this method is affected by the current locale.
6601    * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6602    * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6603    *
6604    * @param str the String to upper case, may be null
6605    * @return the upper cased String, {@code null} if null String input
6606    */
 
6607  3 toggle public static String upperCase(final String str) {
6608  3 if (str == null) {
6609  1 return null;
6610    }
6611  2 return str.toUpperCase();
6612    }
6613   
6614    /**
6615    * <p>Converts a String to upper case as per {@link String#toUpperCase(Locale)}.</p>
6616    *
6617    * <p>A {@code null} input String returns {@code null}.</p>
6618    *
6619    * <pre>
6620    * StringUtils.upperCase(null, Locale.ENGLISH) = null
6621    * StringUtils.upperCase("", Locale.ENGLISH) = ""
6622    * StringUtils.upperCase("aBc", Locale.ENGLISH) = "ABC"
6623    * </pre>
6624    *
6625    * @param str the String to upper case, may be null
6626    * @param locale the locale that defines the case transformation rules, must not be null
6627    * @return the upper cased String, {@code null} if null String input
6628    * @since 2.5
6629    */
 
6630  3 toggle public static String upperCase(final String str, final Locale locale) {
6631  3 if (str == null) {
6632  1 return null;
6633    }
6634  2 return str.toUpperCase(locale);
6635    }
6636   
6637    /**
6638    * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
6639    *
6640    * <p>A {@code null} input String returns {@code null}.</p>
6641    *
6642    * <pre>
6643    * StringUtils.lowerCase(null) = null
6644    * StringUtils.lowerCase("") = ""
6645    * StringUtils.lowerCase("aBc") = "abc"
6646    * </pre>
6647    *
6648    * <p><strong>Note:</strong> As described in the documentation for {@link String#toLowerCase()},
6649    * the result of this method is affected by the current locale.
6650    * For platform-independent case transformations, the method {@link #lowerCase(String, Locale)}
6651    * should be used with a specific locale (e.g. {@link Locale#ENGLISH}).</p>
6652    *
6653    * @param str the String to lower case, may be null
6654    * @return the lower cased String, {@code null} if null String input
6655    */
 
6656  3 toggle public static String lowerCase(final String str) {
6657  3 if (str == null) {
6658  1 return null;
6659    }
6660  2 return str.toLowerCase();
6661    }
6662   
6663    /**
6664    * <p>Converts a String to lower case as per {@link String#toLowerCase(Locale)}.</p>
6665    *
6666    * <p>A {@code null} input String returns {@code null}.</p>
6667    *
6668    * <pre>
6669    * StringUtils.lowerCase(null, Locale.ENGLISH) = null
6670    * StringUtils.lowerCase("", Locale.ENGLISH) = ""
6671    * StringUtils.lowerCase("aBc", Locale.ENGLISH) = "abc"
6672    * </pre>
6673    *
6674    * @param str the String to lower case, may be null
6675    * @param locale the locale that defines the case transformation rules, must not be null
6676    * @return the lower cased String, {@code null} if null String input
6677    * @since 2.5
6678    */
 
6679  3 toggle public static String lowerCase(final String str, final Locale locale) {
6680  3 if (str == null) {
6681  1 return null;
6682    }
6683  2 return str.toLowerCase(locale);
6684    }
6685   
6686    /**
6687    * <p>Capitalizes a String changing the first character to title case as
6688    * per {@link Character#toTitleCase(int)}. No other characters are changed.</p>
6689    *
6690    * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#capitalize(String)}.
6691    * A {@code null} input String returns {@code null}.</p>
6692    *
6693    * <pre>
6694    * StringUtils.capitalize(null) = null
6695    * StringUtils.capitalize("") = ""
6696    * StringUtils.capitalize("cat") = "Cat"
6697    * StringUtils.capitalize("cAt") = "CAt"
6698    * StringUtils.capitalize("'cat'") = "'cat'"
6699    * </pre>
6700    *
6701    * @param str the String to capitalize, may be null
6702    * @return the capitalized String, {@code null} if null String input
6703    * @see org.apache.commons.lang3.text.WordUtils#capitalize(String)
6704    * @see #uncapitalize(String)
6705    * @since 2.0
6706    */
 
6707  15 toggle public static String capitalize(final String str) {
6708  15 int strLen;
6709  ? if (str == null || (strLen = str.length()) == 0) {
6710  4 return str;
6711    }
6712   
6713  11 final int firstCodepoint = str.codePointAt(0);
6714  11 final int newCodePoint = Character.toTitleCase(firstCodepoint);
6715  11 if (firstCodepoint == newCodePoint) {
6716    // already capitalized
6717  2 return str;
6718    }
6719   
6720  9 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6721  9 int outOffset = 0;
6722  9 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6723  39 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6724  30 final int codepoint = str.codePointAt(inOffset);
6725  30 newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6726  30 inOffset += Character.charCount(codepoint);
6727    }
6728  9 return new String(newCodePoints, 0, outOffset);
6729    }
6730   
6731    /**
6732    * <p>Uncapitalizes a String, changing the first character to lower case as
6733    * per {@link Character#toLowerCase(int)}. No other characters are changed.</p>
6734    *
6735    * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#uncapitalize(String)}.
6736    * A {@code null} input String returns {@code null}.</p>
6737    *
6738    * <pre>
6739    * StringUtils.uncapitalize(null) = null
6740    * StringUtils.uncapitalize("") = ""
6741    * StringUtils.uncapitalize("cat") = "cat"
6742    * StringUtils.uncapitalize("Cat") = "cat"
6743    * StringUtils.uncapitalize("CAT") = "cAT"
6744    * </pre>
6745    *
6746    * @param str the String to uncapitalize, may be null
6747    * @return the uncapitalized String, {@code null} if null String input
6748    * @see org.apache.commons.lang3.text.WordUtils#uncapitalize(String)
6749    * @see #capitalize(String)
6750    * @since 2.0
6751    */
 
6752  12 toggle public static String uncapitalize(final String str) {
6753  12 int strLen;
6754  ? if (str == null || (strLen = str.length()) == 0) {
6755  2 return str;
6756    }
6757   
6758  10 final int firstCodepoint = str.codePointAt(0);
6759  10 final int newCodePoint = Character.toLowerCase(firstCodepoint);
6760  10 if (firstCodepoint == newCodePoint) {
6761    // already capitalized
6762  2 return str;
6763    }
6764   
6765  8 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6766  8 int outOffset = 0;
6767  8 newCodePoints[outOffset++] = newCodePoint; // copy the first codepoint
6768  38 for (int inOffset = Character.charCount(firstCodepoint); inOffset < strLen; ) {
6769  30 final int codepoint = str.codePointAt(inOffset);
6770  30 newCodePoints[outOffset++] = codepoint; // copy the remaining ones
6771  30 inOffset += Character.charCount(codepoint);
6772    }
6773  8 return new String(newCodePoints, 0, outOffset);
6774    }
6775   
6776    /**
6777    * <p>Swaps the case of a String changing upper and title case to
6778    * lower case, and lower case to upper case.</p>
6779    *
6780    * <ul>
6781    * <li>Upper case character converts to Lower case</li>
6782    * <li>Title case character converts to Lower case</li>
6783    * <li>Lower case character converts to Upper case</li>
6784    * </ul>
6785    *
6786    * <p>For a word based algorithm, see {@link org.apache.commons.lang3.text.WordUtils#swapCase(String)}.
6787    * A {@code null} input String returns {@code null}.</p>
6788    *
6789    * <pre>
6790    * StringUtils.swapCase(null) = null
6791    * StringUtils.swapCase("") = ""
6792    * StringUtils.swapCase("The dog has a BONE") = "tHE DOG HAS A bone"
6793    * </pre>
6794    *
6795    * <p>NOTE: This method changed in Lang version 2.0.
6796    * It no longer performs a word based algorithm.
6797    * If you only use ASCII, you will notice no change.
6798    * That functionality is available in org.apache.commons.lang3.text.WordUtils.</p>
6799    *
6800    * @param str the String to swap case, may be null
6801    * @return the changed String, {@code null} if null String input
6802    */
 
6803  8 toggle public static String swapCase(final String str) {
6804  8 if (StringUtils.isEmpty(str)) {
6805  2 return str;
6806    }
6807   
6808  6 final int strLen = str.length();
6809  6 final int newCodePoints[] = new int[strLen]; // cannot be longer than the char array
6810  6 int outOffset = 0;
6811  105 for (int i = 0; i < strLen; ) {
6812  99 final int oldCodepoint = str.codePointAt(i);
6813  99 final int newCodePoint;
6814  99 if (Character.isUpperCase(oldCodepoint)) {
6815  18 newCodePoint = Character.toLowerCase(oldCodepoint);
6816  81 } else if (Character.isTitleCase(oldCodepoint)) {
6817  1 newCodePoint = Character.toLowerCase(oldCodepoint);
6818  80 } else if (Character.isLowerCase(oldCodepoint)) {
6819  47 newCodePoint = Character.toUpperCase(oldCodepoint);
6820    } else {
6821  33 newCodePoint = oldCodepoint;
6822    }
6823  99 newCodePoints[outOffset++] = newCodePoint;
6824  99 i += Character.charCount(newCodePoint);
6825    }
6826  6 return new String(newCodePoints, 0, outOffset);
6827    }
6828   
6829    // Count matches
6830    //-----------------------------------------------------------------------
6831    /**
6832    * <p>Counts how many times the substring appears in the larger string.</p>
6833    *
6834    * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6835    *
6836    * <pre>
6837    * StringUtils.countMatches(null, *) = 0
6838    * StringUtils.countMatches("", *) = 0
6839    * StringUtils.countMatches("abba", null) = 0
6840    * StringUtils.countMatches("abba", "") = 0
6841    * StringUtils.countMatches("abba", "a") = 2
6842    * StringUtils.countMatches("abba", "ab") = 1
6843    * StringUtils.countMatches("abba", "xxx") = 0
6844    * </pre>
6845    *
6846    * @param str the CharSequence to check, may be null
6847    * @param sub the substring to count, may be null
6848    * @return the number of occurrences, 0 if either CharSequence is {@code null}
6849    * @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
6850    */
 
6851  9 toggle public static int countMatches(final CharSequence str, final CharSequence sub) {
6852  9 if (isEmpty(str) || isEmpty(sub)) {
6853  5 return 0;
6854    }
6855  4 int count = 0;
6856  4 int idx = 0;
6857  ? while ((idx = CharSequenceUtils.indexOf(str, sub, idx)) != INDEX_NOT_FOUND) {
6858  11 count++;
6859  11 idx += sub.length();
6860    }
6861  4 return count;
6862    }
6863   
6864    /**
6865    * <p>Counts how many times the char appears in the given string.</p>
6866    *
6867    * <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
6868    *
6869    * <pre>
6870    * StringUtils.countMatches(null, *) = 0
6871    * StringUtils.countMatches("", *) = 0
6872    * StringUtils.countMatches("abba", 0) = 0
6873    * StringUtils.countMatches("abba", 'a') = 2
6874    * StringUtils.countMatches("abba", 'b') = 2
6875    * StringUtils.countMatches("abba", 'x') = 0
6876    * </pre>
6877    *
6878    * @param str the CharSequence to check, may be null
6879    * @param ch the char to count
6880    * @return the number of occurrences, 0 if the CharSequence is {@code null}
6881    * @since 3.4
6882    */
 
6883  10 toggle public static int countMatches(final CharSequence str, final char ch) {
6884  10 if (isEmpty(str)) {
6885  1 return 0;
6886    }
6887  9 int count = 0;
6888    // We could also call str.toCharArray() for faster look ups but that would generate more garbage.
6889  183 for (int i = 0; i < str.length(); i++) {
6890  174 if (ch == str.charAt(i)) {
6891  23 count++;
6892    }
6893    }
6894  9 return count;
6895    }
6896   
6897    // Character Tests
6898    //-----------------------------------------------------------------------
6899    /**
6900    * <p>Checks if the CharSequence contains only Unicode letters.</p>
6901    *
6902    * <p>{@code null} will return {@code false}.
6903    * An empty CharSequence (length()=0) will return {@code false}.</p>
6904    *
6905    * <pre>
6906    * StringUtils.isAlpha(null) = false
6907    * StringUtils.isAlpha("") = false
6908    * StringUtils.isAlpha(" ") = false
6909    * StringUtils.isAlpha("abc") = true
6910    * StringUtils.isAlpha("ab2c") = false
6911    * StringUtils.isAlpha("ab-c") = false
6912    * </pre>
6913    *
6914    * @param cs the CharSequence to check, may be null
6915    * @return {@code true} if only contains letters, and is non-null
6916    * @since 3.0 Changed signature from isAlpha(String) to isAlpha(CharSequence)
6917    * @since 3.0 Changed "" to return false and not true
6918    */
 
6919  11 toggle public static boolean isAlpha(final CharSequence cs) {
6920  11 if (isEmpty(cs)) {
6921  2 return false;
6922    }
6923  9 final int sz = cs.length();
6924  58 for (int i = 0; i < sz; i++) {
6925  55 if (Character.isLetter(cs.charAt(i)) == false) {
6926  6 return false;
6927    }
6928    }
6929  3 return true;
6930    }
6931   
6932    /**
6933    * <p>Checks if the CharSequence contains only Unicode letters and
6934    * space (' ').</p>
6935    *
6936    * <p>{@code null} will return {@code false}
6937    * An empty CharSequence (length()=0) will return {@code true}.</p>
6938    *
6939    * <pre>
6940    * StringUtils.isAlphaSpace(null) = false
6941    * StringUtils.isAlphaSpace("") = true
6942    * StringUtils.isAlphaSpace(" ") = true
6943    * StringUtils.isAlphaSpace("abc") = true
6944    * StringUtils.isAlphaSpace("ab c") = true
6945    * StringUtils.isAlphaSpace("ab2c") = false
6946    * StringUtils.isAlphaSpace("ab-c") = false
6947    * </pre>
6948    *
6949    * @param cs the CharSequence to check, may be null
6950    * @return {@code true} if only contains letters and space,
6951    * and is non-null
6952    * @since 3.0 Changed signature from isAlphaSpace(String) to isAlphaSpace(CharSequence)
6953    */
 
6954  11 toggle public static boolean isAlphaSpace(final CharSequence cs) {
6955  11 if (cs == null) {
6956  1 return false;
6957    }
6958  10 final int sz = cs.length();
6959  64 for (int i = 0; i < sz; i++) {
6960  58 if (Character.isLetter(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
6961  4 return false;
6962    }
6963    }
6964  6 return true;
6965    }
6966   
6967    /**
6968    * <p>Checks if the CharSequence contains only Unicode letters or digits.</p>
6969    *
6970    * <p>{@code null} will return {@code false}.
6971    * An empty CharSequence (length()=0) will return {@code false}.</p>
6972    *
6973    * <pre>
6974    * StringUtils.isAlphanumeric(null) = false
6975    * StringUtils.isAlphanumeric("") = false
6976    * StringUtils.isAlphanumeric(" ") = false
6977    * StringUtils.isAlphanumeric("abc") = true
6978    * StringUtils.isAlphanumeric("ab c") = false
6979    * StringUtils.isAlphanumeric("ab2c") = true
6980    * StringUtils.isAlphanumeric("ab-c") = false
6981    * </pre>
6982    *
6983    * @param cs the CharSequence to check, may be null
6984    * @return {@code true} if only contains letters or digits,
6985    * and is non-null
6986    * @since 3.0 Changed signature from isAlphanumeric(String) to isAlphanumeric(CharSequence)
6987    * @since 3.0 Changed "" to return false and not true
6988    */
 
6989  11 toggle public static boolean isAlphanumeric(final CharSequence cs) {
6990  11 if (isEmpty(cs)) {
6991  2 return false;
6992    }
6993  9 final int sz = cs.length();
6994  84 for (int i = 0; i < sz; i++) {
6995  79 if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
6996  4 return false;
6997    }
6998    }
6999  5 return true;
7000    }
7001   
7002    /**
7003    * <p>Checks if the CharSequence contains only Unicode letters, digits
7004    * or space ({@code ' '}).</p>
7005    *
7006    * <p>{@code null} will return {@code false}.
7007    * An empty CharSequence (length()=0) will return {@code true}.</p>
7008    *
7009    * <pre>
7010    * StringUtils.isAlphanumericSpace(null) = false
7011    * StringUtils.isAlphanumericSpace("") = true
7012    * StringUtils.isAlphanumericSpace(" ") = true
7013    * StringUtils.isAlphanumericSpace("abc") = true
7014    * StringUtils.isAlphanumericSpace("ab c") = true
7015    * StringUtils.isAlphanumericSpace("ab2c") = true
7016    * StringUtils.isAlphanumericSpace("ab-c") = false
7017    * </pre>
7018    *
7019    * @param cs the CharSequence to check, may be null
7020    * @return {@code true} if only contains letters, digits or space,
7021    * and is non-null
7022    * @since 3.0 Changed signature from isAlphanumericSpace(String) to isAlphanumericSpace(CharSequence)
7023    */
 
7024  11 toggle public static boolean isAlphanumericSpace(final CharSequence cs) {
7025  11 if (cs == null) {
7026  1 return false;
7027    }
7028  10 final int sz = cs.length();
7029  90 for (int i = 0; i < sz; i++) {
7030  82 if (Character.isLetterOrDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
7031  2 return false;
7032    }
7033    }
7034  8 return true;
7035    }
7036   
7037    /**
7038    * <p>Checks if the CharSequence contains only ASCII printable characters.</p>
7039    *
7040    * <p>{@code null} will return {@code false}.
7041    * An empty CharSequence (length()=0) will return {@code true}.</p>
7042    *
7043    * <pre>
7044    * StringUtils.isAsciiPrintable(null) = false
7045    * StringUtils.isAsciiPrintable("") = true
7046    * StringUtils.isAsciiPrintable(" ") = true
7047    * StringUtils.isAsciiPrintable("Ceki") = true
7048    * StringUtils.isAsciiPrintable("ab2c") = true
7049    * StringUtils.isAsciiPrintable("!ab-c~") = true
7050    * StringUtils.isAsciiPrintable("\u0020") = true
7051    * StringUtils.isAsciiPrintable("\u0021") = true
7052    * StringUtils.isAsciiPrintable("\u007e") = true
7053    * StringUtils.isAsciiPrintable("\u007f") = false
7054    * StringUtils.isAsciiPrintable("Ceki G\u00fclc\u00fc") = false
7055    * </pre>
7056    *
7057    * @param cs the CharSequence to check, may be null
7058    * @return {@code true} if every character is in the range
7059    * 32 thru 126
7060    * @since 2.1
7061    * @since 3.0 Changed signature from isAsciiPrintable(String) to isAsciiPrintable(CharSequence)
7062    */
 
7063  22 toggle public static boolean isAsciiPrintable(final CharSequence cs) {
7064  22 if (cs == null) {
7065  1 return false;
7066    }
7067  21 final int sz = cs.length();
7068  135 for (int i = 0; i < sz; i++) {
7069  117 if (CharUtils.isAsciiPrintable(cs.charAt(i)) == false) {
7070  3 return false;
7071    }
7072    }
7073  18 return true;
7074    }
7075   
7076    /**
7077    * <p>Checks if the CharSequence contains only Unicode digits.
7078    * A decimal point is not a Unicode digit and returns false.</p>
7079    *
7080    * <p>{@code null} will return {@code false}.
7081    * An empty CharSequence (length()=0) will return {@code false}.</p>
7082    *
7083    * <p>Note that the method does not allow for a leading sign, either positive or negative.
7084    * Also, if a String passes the numeric test, it may still generate a NumberFormatException
7085    * when parsed by Integer.parseInt or Long.parseLong, e.g. if the value is outside the range
7086    * for int or long respectively.</p>
7087    *
7088    * <pre>
7089    * StringUtils.isNumeric(null) = false
7090    * StringUtils.isNumeric("") = false
7091    * StringUtils.isNumeric(" ") = false
7092    * StringUtils.isNumeric("123") = true
7093    * StringUtils.isNumeric("\u0967\u0968\u0969") = true
7094    * StringUtils.isNumeric("12 3") = false
7095    * StringUtils.isNumeric("ab2c") = false
7096    * StringUtils.isNumeric("12-3") = false
7097    * StringUtils.isNumeric("12.3") = false
7098    * StringUtils.isNumeric("-123") = false
7099    * StringUtils.isNumeric("+123") = false
7100    * </pre>
7101    *
7102    * @param cs the CharSequence to check, may be null
7103    * @return {@code true} if only contains digits, and is non-null
7104    * @since 3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence)
7105    * @since 3.0 Changed "" to return false and not true
7106    */
 
7107  45 toggle public static boolean isNumeric(final CharSequence cs) {
7108  45 if (isEmpty(cs)) {
7109  4 return false;
7110    }
7111  41 final int sz = cs.length();
7112  135 for (int i = 0; i < sz; i++) {
7113  117 if (!Character.isDigit(cs.charAt(i))) {
7114  23 return false;
7115    }
7116    }
7117  18 return true;
7118    }
7119   
7120    /**
7121    * <p>Checks if the CharSequence contains only Unicode digits or space
7122    * ({@code ' '}).
7123    * A decimal point is not a Unicode digit and returns false.</p>
7124    *
7125    * <p>{@code null} will return {@code false}.
7126    * An empty CharSequence (length()=0) will return {@code true}.</p>
7127    *
7128    * <pre>
7129    * StringUtils.isNumericSpace(null) = false
7130    * StringUtils.isNumericSpace("") = true
7131    * StringUtils.isNumericSpace(" ") = true
7132    * StringUtils.isNumericSpace("123") = true
7133    * StringUtils.isNumericSpace("12 3") = true
7134    * StringUtils.isNumeric("\u0967\u0968\u0969") = true
7135    * StringUtils.isNumeric("\u0967\u0968 \u0969") = true
7136    * StringUtils.isNumericSpace("ab2c") = false
7137    * StringUtils.isNumericSpace("12-3") = false
7138    * StringUtils.isNumericSpace("12.3") = false
7139    * </pre>
7140    *
7141    * @param cs the CharSequence to check, may be null
7142    * @return {@code true} if only contains digits or space,
7143    * and is non-null
7144    * @since 3.0 Changed signature from isNumericSpace(String) to isNumericSpace(CharSequence)
7145    */
 
7146  16 toggle public static boolean isNumericSpace(final CharSequence cs) {
7147  16 if (cs == null) {
7148  1 return false;
7149    }
7150  15 final int sz = cs.length();
7151  34 for (int i = 0; i < sz; i++) {
7152  27 if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
7153  8 return false;
7154    }
7155    }
7156  7 return true;
7157    }
7158   
7159    /**
7160    * <p>Checks if the CharSequence contains only whitespace.</p>
7161    *
7162    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7163    *
7164    * <p>{@code null} will return {@code false}.
7165    * An empty CharSequence (length()=0) will return {@code true}.</p>
7166    *
7167    * <pre>
7168    * StringUtils.isWhitespace(null) = false
7169    * StringUtils.isWhitespace("") = true
7170    * StringUtils.isWhitespace(" ") = true
7171    * StringUtils.isWhitespace("abc") = false
7172    * StringUtils.isWhitespace("ab2c") = false
7173    * StringUtils.isWhitespace("ab-c") = false
7174    * </pre>
7175    *
7176    * @param cs the CharSequence to check, may be null
7177    * @return {@code true} if only contains whitespace, and is non-null
7178    * @since 2.0
7179    * @since 3.0 Changed signature from isWhitespace(String) to isWhitespace(CharSequence)
7180    */
 
7181  12 toggle public static boolean isWhitespace(final CharSequence cs) {
7182  12 if (cs == null) {
7183  1 return false;
7184    }
7185  11 final int sz = cs.length();
7186  49 for (int i = 0; i < sz; i++) {
7187  44 if (Character.isWhitespace(cs.charAt(i)) == false) {
7188  6 return false;
7189    }
7190    }
7191  5 return true;
7192    }
7193   
7194    /**
7195    * <p>Checks if the CharSequence contains only lowercase characters.</p>
7196    *
7197    * <p>{@code null} will return {@code false}.
7198    * An empty CharSequence (length()=0) will return {@code false}.</p>
7199    *
7200    * <pre>
7201    * StringUtils.isAllLowerCase(null) = false
7202    * StringUtils.isAllLowerCase("") = false
7203    * StringUtils.isAllLowerCase(" ") = false
7204    * StringUtils.isAllLowerCase("abc") = true
7205    * StringUtils.isAllLowerCase("abC") = false
7206    * StringUtils.isAllLowerCase("ab c") = false
7207    * StringUtils.isAllLowerCase("ab1c") = false
7208    * StringUtils.isAllLowerCase("ab/c") = false
7209    * </pre>
7210    *
7211    * @param cs the CharSequence to check, may be null
7212    * @return {@code true} if only contains lowercase characters, and is non-null
7213    * @since 2.5
7214    * @since 3.0 Changed signature from isAllLowerCase(String) to isAllLowerCase(CharSequence)
7215    */
 
7216  353 toggle public static boolean isAllLowerCase(final CharSequence cs) {
7217  353 if (cs == null || isEmpty(cs)) {
7218  2 return false;
7219    }
7220  351 final int sz = cs.length();
7221  1049 for (int i = 0; i < sz; i++) {
7222  850 if (Character.isLowerCase(cs.charAt(i)) == false) {
7223  152 return false;
7224    }
7225    }
7226  199 return true;
7227    }
7228   
7229    /**
7230    * <p>Checks if the CharSequence contains only uppercase characters.</p>
7231    *
7232    * <p>{@code null} will return {@code false}.
7233    * An empty String (length()=0) will return {@code false}.</p>
7234    *
7235    * <pre>
7236    * StringUtils.isAllUpperCase(null) = false
7237    * StringUtils.isAllUpperCase("") = false
7238    * StringUtils.isAllUpperCase(" ") = false
7239    * StringUtils.isAllUpperCase("ABC") = true
7240    * StringUtils.isAllUpperCase("aBC") = false
7241    * StringUtils.isAllUpperCase("A C") = false
7242    * StringUtils.isAllUpperCase("A1C") = false
7243    * StringUtils.isAllUpperCase("A/C") = false
7244    * </pre>
7245    *
7246    * @param cs the CharSequence to check, may be null
7247    * @return {@code true} if only contains uppercase characters, and is non-null
7248    * @since 2.5
7249    * @since 3.0 Changed signature from isAllUpperCase(String) to isAllUpperCase(CharSequence)
7250    */
 
7251  147 toggle public static boolean isAllUpperCase(final CharSequence cs) {
7252  147 if (cs == null || isEmpty(cs)) {
7253  2 return false;
7254    }
7255  145 final int sz = cs.length();
7256  414 for (int i = 0; i < sz; i++) {
7257  286 if (Character.isUpperCase(cs.charAt(i)) == false) {
7258  17 return false;
7259    }
7260    }
7261  128 return true;
7262    }
7263   
7264    // Defaults
7265    //-----------------------------------------------------------------------
7266    /**
7267    * <p>Returns either the passed in String,
7268    * or if the String is {@code null}, an empty String ("").</p>
7269    *
7270    * <pre>
7271    * StringUtils.defaultString(null) = ""
7272    * StringUtils.defaultString("") = ""
7273    * StringUtils.defaultString("bat") = "bat"
7274    * </pre>
7275    *
7276    * @see ObjectUtils#toString(Object)
7277    * @see String#valueOf(Object)
7278    * @param str the String to check, may be null
7279    * @return the passed in String, or the empty String if it
7280    * was {@code null}
7281    */
 
7282  7 toggle public static String defaultString(final String str) {
7283  7 return str == null ? EMPTY : str;
7284    }
7285   
7286    /**
7287    * <p>Returns either the passed in String, or if the String is
7288    * {@code null}, the value of {@code defaultStr}.</p>
7289    *
7290    * <pre>
7291    * StringUtils.defaultString(null, "NULL") = "NULL"
7292    * StringUtils.defaultString("", "NULL") = ""
7293    * StringUtils.defaultString("bat", "NULL") = "bat"
7294    * </pre>
7295    *
7296    * @see ObjectUtils#toString(Object,String)
7297    * @see String#valueOf(Object)
7298    * @param str the String to check, may be null
7299    * @param defaultStr the default String to return
7300    * if the input is {@code null}, may be null
7301    * @return the passed in String, or the default if it was {@code null}
7302    */
 
7303  9 toggle public static String defaultString(final String str, final String defaultStr) {
7304  9 return str == null ? defaultStr : str;
7305    }
7306   
7307    /**
7308    * <p>Returns either the passed in CharSequence, or if the CharSequence is
7309    * whitespace, empty ("") or {@code null}, the value of {@code defaultStr}.</p>
7310    *
7311    * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
7312    *
7313    * <pre>
7314    * StringUtils.defaultIfBlank(null, "NULL") = "NULL"
7315    * StringUtils.defaultIfBlank("", "NULL") = "NULL"
7316    * StringUtils.defaultIfBlank(" ", "NULL") = "NULL"
7317    * StringUtils.defaultIfBlank("bat", "NULL") = "bat"
7318    * StringUtils.defaultIfBlank("", null) = null
7319    * </pre>
7320    * @param <T> the specific kind of CharSequence
7321    * @param str the CharSequence to check, may be null
7322    * @param defaultStr the default CharSequence to return
7323    * if the input is whitespace, empty ("") or {@code null}, may be null
7324    * @return the passed in CharSequence, or the default
7325    * @see StringUtils#defaultString(String, String)
7326    */
 
7327  21 toggle public static <T extends CharSequence> T defaultIfBlank(final T str, final T defaultStr) {
7328  21 return isBlank(str) ? defaultStr : str;
7329    }
7330   
7331    /**
7332    * <p>Returns either the passed in CharSequence, or if the CharSequence is
7333    * empty or {@code null}, the value of {@code defaultStr}.</p>
7334    *
7335    * <pre>
7336    * StringUtils.defaultIfEmpty(null, "NULL") = "NULL"
7337    * StringUtils.defaultIfEmpty("", "NULL") = "NULL"
7338    * StringUtils.defaultIfEmpty(" ", "NULL") = " "
7339    * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
7340    * StringUtils.defaultIfEmpty("", null) = null
7341    * </pre>
7342    * @param <T> the specific kind of CharSequence
7343    * @param str the CharSequence to check, may be null
7344    * @param defaultStr the default CharSequence to return
7345    * if the input is empty ("") or {@code null}, may be null
7346    * @return the passed in CharSequence, or the default
7347    * @see StringUtils#defaultString(String, String)
7348    */
 
7349  17 toggle public static <T extends CharSequence> T defaultIfEmpty(final T str, final T defaultStr) {
7350  17 return isEmpty(str) ? defaultStr : str;
7351    }
7352   
7353    // Rotating (circular shift)
7354    //-----------------------------------------------------------------------
7355    /**
7356    * <p>Rotate (circular shift) a String of {@code shift} characters.</p>
7357    * <ul>
7358    * <li>If {@code shift > 0}, right circular shift (ex : ABCDEF =&gt; FABCDE)</li>
7359    * <li>If {@code shift < 0}, left circular shift (ex : ABCDEF =&gt; BCDEFA)</li>
7360    * </ul>
7361    *
7362    * <pre>
7363    * StringUtils.rotate(null, *) = null
7364    * StringUtils.rotate("", *) = ""
7365    * StringUtils.rotate("abcdefg", 0) = "abcdefg"
7366    * StringUtils.rotate("abcdefg", 2) = "fgabcde"
7367    * StringUtils.rotate("abcdefg", -2) = "cdefgab"
7368    * StringUtils.rotate("abcdefg", 7) = "abcdefg"
7369    * StringUtils.rotate("abcdefg", -7) = "abcdefg"
7370    * StringUtils.rotate("abcdefg", 9) = "fgabcde"
7371    * StringUtils.rotate("abcdefg", -9) = "cdefgab"
7372    * </pre>
7373    *
7374    * @param str the String to rotate, may be null
7375    * @param shift number of time to shift (positive : right shift, negative : left shift)
7376    * @return the rotated String,
7377    * or the original String if {@code shift == 0},
7378    * or {@code null} if null String input
7379    * @since 3.5
7380    */
 
7381  11 toggle public static String rotate(final String str, final int shift) {
7382  11 if (str == null) {
7383  1 return null;
7384    }
7385   
7386  10 final int strLen = str.length();
7387  10 if (shift == 0 || strLen == 0 || shift % strLen == 0) {
7388  4 return str;
7389    }
7390   
7391  6 final StringBuilder builder = new StringBuilder(strLen);
7392  6 final int offset = - (shift % strLen);
7393  6 builder.append(substring(str, offset));
7394  6 builder.append(substring(str, 0, offset));
7395  6 return builder.toString();
7396    }
7397   
7398    // Reversing
7399    //-----------------------------------------------------------------------
7400    /**
7401    * <p>Reverses a String as per {@link StringBuilder#reverse()}.</p>
7402    *
7403    * <p>A {@code null} String returns {@code null}.</p>
7404    *
7405    * <pre>
7406    * StringUtils.reverse(null) = null
7407    * StringUtils.reverse("") = ""
7408    * StringUtils.reverse("bat") = "tab"
7409    * </pre>
7410    *
7411    * @param str the String to reverse, may be null
7412    * @return the reversed String, {@code null} if null String input
7413    */
 
7414  3 toggle public static String reverse(final String str) {
7415  3 if (str == null) {
7416  1 return null;
7417    }
7418  2 return new StringBuilder(str).reverse().toString();
7419    }
7420   
7421    /**
7422    * <p>Reverses a String that is delimited by a specific character.</p>
7423    *
7424    * <p>The Strings between the delimiters are not reversed.
7425    * Thus java.lang.String becomes String.lang.java (if the delimiter
7426    * is {@code '.'}).</p>
7427    *
7428    * <pre>
7429    * StringUtils.reverseDelimited(null, *) = null
7430    * StringUtils.reverseDelimited("", *) = ""
7431    * StringUtils.reverseDelimited("a.b.c", 'x') = "a.b.c"
7432    * StringUtils.reverseDelimited("a.b.c", ".") = "c.b.a"
7433    * </pre>
7434    *
7435    * @param str the String to reverse, may be null
7436    * @param separatorChar the separator character to use
7437    * @return the reversed String, {@code null} if null String input
7438    * @since 2.0
7439    */
 
7440  5 toggle public static String reverseDelimited(final String str, final char separatorChar) {
7441  5 if (str == null) {
7442  1 return null;
7443    }
7444    // could implement manually, but simple way is to reuse other,
7445    // probably slower, methods.
7446  4 final String[] strs = split(str, separatorChar);
7447  4 ArrayUtils.reverse(strs);
7448  4 return join(strs, separatorChar);
7449    }
7450   
7451    // Abbreviating
7452    //-----------------------------------------------------------------------
7453    /**
7454    * <p>Abbreviates a String using ellipses. This will turn
7455    * "Now is the time for all good men" into "Now is the time for..."</p>
7456    *
7457    * <p>Specifically:</p>
7458    * <ul>
7459    * <li>If the number of characters in {@code str} is less than or equal to
7460    * {@code maxWidth}, return {@code str}.</li>
7461    * <li>Else abbreviate it to {@code (substring(str, 0, max-3) + "...")}.</li>
7462    * <li>If {@code maxWidth} is less than {@code 4}, throw an
7463    * {@code IllegalArgumentException}.</li>
7464    * <li>In no case will it return a String of length greater than
7465    * {@code maxWidth}.</li>
7466    * </ul>
7467    *
7468    * <pre>
7469    * StringUtils.abbreviate(null, *) = null
7470    * StringUtils.abbreviate("", 4) = ""
7471    * StringUtils.abbreviate("abcdefg", 6) = "abc..."
7472    * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
7473    * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
7474    * StringUtils.abbreviate("abcdefg", 4) = "a..."
7475    * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
7476    * </pre>
7477    *
7478    * @param str the String to check, may be null
7479    * @param maxWidth maximum length of result String, must be at least 4
7480    * @return abbreviated String, {@code null} if null String input
7481    * @throws IllegalArgumentException if the width is too small
7482    * @since 2.0
7483    */
 
7484  14 toggle public static String abbreviate(final String str, final int maxWidth) {
7485  14 final String defaultAbbrevMarker = "...";
7486  14 return abbreviate(str, defaultAbbrevMarker, 0, maxWidth);
7487    }
7488   
7489    /**
7490    * <p>Abbreviates a String using ellipses. This will turn
7491    * "Now is the time for all good men" into "...is the time for..."</p>
7492    *
7493    * <p>Works like {@code abbreviate(String, int)}, but allows you to specify
7494    * a "left edge" offset. Note that this left edge is not necessarily going to
7495    * be the leftmost character in the result, or the first character following the
7496    * ellipses, but it will appear somewhere in the result.
7497    *
7498    * <p>In no case will it return a String of length greater than
7499    * {@code maxWidth}.</p>
7500    *
7501    * <pre>
7502    * StringUtils.abbreviate(null, *, *) = null
7503    * StringUtils.abbreviate("", 0, 4) = ""
7504    * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
7505    * StringUtils.abbreviate("abcdefghijklmno", 0, 10) = "abcdefg..."
7506    * StringUtils.abbreviate("abcdefghijklmno", 1, 10) = "abcdefg..."
7507    * StringUtils.abbreviate("abcdefghijklmno", 4, 10) = "abcdefg..."
7508    * StringUtils.abbreviate("abcdefghijklmno", 5, 10) = "...fghi..."
7509    * StringUtils.abbreviate("abcdefghijklmno", 6, 10) = "...ghij..."
7510    * StringUtils.abbreviate("abcdefghijklmno", 8, 10) = "...ijklmno"
7511    * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
7512    * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
7513    * StringUtils.abbreviate("abcdefghij", 0, 3) = IllegalArgumentException
7514    * StringUtils.abbreviate("abcdefghij", 5, 6) = IllegalArgumentException
7515    * </pre>
7516    *
7517    * @param str the String to check, may be null
7518    * @param offset left edge of source String
7519    * @param maxWidth maximum length of result String, must be at least 4
7520    * @return abbreviated String, {@code null} if null String input
7521    * @throws IllegalArgumentException if the width is too small
7522    * @since 2.0
7523    */
 
7524  27 toggle public static String abbreviate(final String str, final int offset, final int maxWidth) {
7525  27 final String defaultAbbrevMarker = "...";
7526  27 return abbreviate(str, defaultAbbrevMarker, offset, maxWidth);
7527    }
7528   
7529    /**
7530    * <p>Abbreviates a String using another given String as replacement marker. This will turn
7531    * "Now is the time for all good men" into "Now is the time for..." if "..." was defined
7532    * as the replacement marker.</p>
7533    *
7534    * <p>Specifically:</p>
7535    * <ul>
7536    * <li>If the number of characters in {@code str} is less than or equal to
7537    * {@code maxWidth}, return {@code str}.</li>
7538    * <li>Else abbreviate it to {@code (substring(str, 0, max-abbrevMarker.length) + abbrevMarker)}.</li>
7539    * <li>If {@code maxWidth} is less than {@code abbrevMarker.length + 1}, throw an
7540    * {@code IllegalArgumentException}.</li>
7541    * <li>In no case will it return a String of length greater than
7542    * {@code maxWidth}.</li>
7543    * </ul>
7544    *
7545    * <pre>
7546    * StringUtils.abbreviate(null, "...", *) = null
7547    * StringUtils.abbreviate("abcdefg", null, *) = "abcdefg"
7548    * StringUtils.abbreviate("", "...", 4) = ""
7549    * StringUtils.abbreviate("abcdefg", ".", 5) = "abcd."
7550    * StringUtils.abbreviate("abcdefg", ".", 7) = "abcdefg"
7551    * StringUtils.abbreviate("abcdefg", ".", 8) = "abcdefg"
7552    * StringUtils.abbreviate("abcdefg", "..", 4) = "ab.."
7553    * StringUtils.abbreviate("abcdefg", "..", 3) = "a.."
7554    * StringUtils.abbreviate("abcdefg", "..", 2) = IllegalArgumentException
7555    * StringUtils.abbreviate("abcdefg", "...", 3) = IllegalArgumentException
7556    * </pre>
7557    *
7558    * @param str the String to check, may be null
7559    * @param abbrevMarker the String used as replacement marker
7560    * @param maxWidth maximum length of result String, must be at least {@code abbrevMarker.length + 1}
7561    * @return abbreviated String, {@code null} if null String input
7562    * @throws IllegalArgumentException if the width is too small
7563    * @since 3.6
7564    */
 
7565  19 toggle public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) {
7566  19 return abbreviate(str, abbrevMarker, 0, maxWidth);
7567    }
7568   
7569    /**
7570    * <p>Abbreviates a String using a given replacement marker. This will turn
7571    * "Now is the time for all good men" into "...is the time for..." if "..." was defined
7572    * as the replacement marker.</p>
7573    *
7574    * <p>Works like {@code abbreviate(String, String, int)}, but allows you to specify
7575    * a "left edge" offset. Note that this left edge is not necessarily going to
7576    * be the leftmost character in the result, or the first character following the
7577    * replacement marker, but it will appear somewhere in the result.
7578    *
7579    * <p>In no case will it return a String of length greater than {@code maxWidth}.</p>
7580    *
7581    * <pre>
7582    * StringUtils.abbreviate(null, null, *, *) = null
7583    * StringUtils.abbreviate("abcdefghijklmno", null, *, *) = "abcdefghijklmno"
7584    * StringUtils.abbreviate("", "...", 0, 4) = ""
7585    * StringUtils.abbreviate("abcdefghijklmno", "---", -1, 10) = "abcdefg---"
7586    * StringUtils.abbreviate("abcdefghijklmno", ",", 0, 10) = "abcdefghi,"
7587    * StringUtils.abbreviate("abcdefghijklmno", ",", 1, 10) = "abcdefghi,"
7588    * StringUtils.abbreviate("abcdefghijklmno", ",", 2, 10) = "abcdefghi,"
7589    * StringUtils.abbreviate("abcdefghijklmno", "::", 4, 10) = "::efghij::"
7590    * StringUtils.abbreviate("abcdefghijklmno", "...", 6, 10) = "...ghij..."
7591    * StringUtils.abbreviate("abcdefghijklmno", "*", 9, 10) = "*ghijklmno"
7592    * StringUtils.abbreviate("abcdefghijklmno", "'", 10, 10) = "'ghijklmno"
7593    * StringUtils.abbreviate("abcdefghijklmno", "!", 12, 10) = "!ghijklmno"
7594    * StringUtils.abbreviate("abcdefghij", "abra", 0, 4) = IllegalArgumentException
7595    * StringUtils.abbreviate("abcdefghij", "...", 5, 6) = IllegalArgumentException
7596    * </pre>
7597    *
7598    * @param str the String to check, may be null
7599    * @param abbrevMarker the String used as replacement marker
7600    * @param offset left edge of source String
7601    * @param maxWidth maximum length of result String, must be at least 4
7602    * @return abbreviated String, {@code null} if null String input
7603    * @throws IllegalArgumentException if the width is too small
7604    * @since 3.6
7605    */
 
7606  88 toggle public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) {
7607  88 if (isEmpty(str) || isEmpty(abbrevMarker)) {
7608  17 return str;
7609    }
7610   
7611  71 final int abbrevMarkerLength = abbrevMarker.length();
7612  71 final int minAbbrevWidth = abbrevMarkerLength + 1;
7613  71 final int minAbbrevWidthOffset = abbrevMarkerLength + abbrevMarkerLength + 1;
7614   
7615  71 if (maxWidth < minAbbrevWidth) {
7616  4 throw new IllegalArgumentException(String.format("Minimum abbreviation width is %d", minAbbrevWidth));
7617    }
7618  67 if (str.length() <= maxWidth) {
7619  11 return str;
7620    }
7621  56 if (offset > str.length()) {
7622  4 offset = str.length();
7623    }
7624  56 if (str.length() - offset < maxWidth - abbrevMarkerLength) {
7625  22 offset = str.length() - (maxWidth - abbrevMarkerLength);
7626    }
7627  56 if (offset <= abbrevMarkerLength+1) {
7628  26 return str.substring(0, maxWidth - abbrevMarkerLength) + abbrevMarker;
7629    }
7630  30 if (maxWidth < minAbbrevWidthOffset) {
7631  2 throw new IllegalArgumentException(String.format("Minimum abbreviation width with offset is %d", minAbbrevWidthOffset));
7632    }
7633  28 if (offset + maxWidth - abbrevMarkerLength < str.length()) {
7634  5 return abbrevMarker + abbreviate(str.substring(offset), abbrevMarker, maxWidth - abbrevMarkerLength);
7635    }
7636  23 return abbrevMarker + str.substring(str.length() - (maxWidth - abbrevMarkerLength));
7637    }
7638   
7639    /**
7640    * <p>Abbreviates a String to the length passed, replacing the middle characters with the supplied
7641    * replacement String.</p>
7642    *
7643    * <p>This abbreviation only occurs if the following criteria is met:</p>
7644    * <ul>
7645    * <li>Neither the String for abbreviation nor the replacement String are null or empty </li>
7646    * <li>The length to truncate to is less than the length of the supplied String</li>
7647    * <li>The length to truncate to is greater than 0</li>
7648    * <li>The abbreviated String will have enough room for the length supplied replacement String
7649    * and the first and last characters of the supplied String for abbreviation</li>
7650    * </ul>
7651    * <p>Otherwise, the returned String will be the same as the supplied String for abbreviation.
7652    * </p>
7653    *
7654    * <pre>
7655    * StringUtils.abbreviateMiddle(null, null, 0) = null
7656    * StringUtils.abbreviateMiddle("abc", null, 0) = "abc"
7657    * StringUtils.abbreviateMiddle("abc", ".", 0) = "abc"
7658    * StringUtils.abbreviateMiddle("abc", ".", 3) = "abc"
7659    * StringUtils.abbreviateMiddle("abcdef", ".", 4) = "ab.f"
7660    * </pre>
7661    *
7662    * @param str the String to abbreviate, may be null
7663    * @param middle the String to replace the middle characters with, may be null
7664    * @param length the length to abbreviate {@code str} to.
7665    * @return the abbreviated String if the above criteria is met, or the original String supplied for abbreviation.
7666    * @since 2.5
7667    */
 
7668  14 toggle public static String abbreviateMiddle(final String str, final String middle, final int length) {
7669  14 if (isEmpty(str) || isEmpty(middle)) {
7670  2 return str;
7671    }
7672   
7673  12 if (length >= str.length() || length < middle.length()+2) {
7674  6 return str;
7675    }
7676   
7677  6 final int targetSting = length-middle.length();
7678  6 final int startOffset = targetSting/2+targetSting%2;
7679  6 final int endOffset = str.length()-targetSting/2;
7680   
7681  6 final StringBuilder builder = new StringBuilder(length);
7682  6 builder.append(str.substring(0,startOffset));
7683  6 builder.append(middle);
7684  6 builder.append(str.substring(endOffset));
7685   
7686  6 return builder.toString();
7687    }
7688   
7689    // Difference
7690    //-----------------------------------------------------------------------
7691    /**
7692    * <p>Compares two Strings, and returns the portion where they differ.
7693    * More precisely, return the remainder of the second String,
7694    * starting from where it's different from the first. This means that
7695    * the difference between "abc" and "ab" is the empty String and not "c". </p>
7696    *
7697    * <p>For example,
7698    * {@code difference("i am a machine", "i am a robot") -> "robot"}.</p>
7699    *
7700    * <pre>
7701    * StringUtils.difference(null, null) = null
7702    * StringUtils.difference("", "") = ""
7703    * StringUtils.difference("", "abc") = "abc"
7704    * StringUtils.difference("abc", "") = ""
7705    * StringUtils.difference("abc", "abc") = ""
7706    * StringUtils.difference("abc", "ab") = ""
7707    * StringUtils.difference("ab", "abxyz") = "xyz"
7708    * StringUtils.difference("abcde", "abxyz") = "xyz"
7709    * StringUtils.difference("abcde", "xyz") = "xyz"
7710    * </pre>
7711    *
7712    * @param str1 the first String, may be null
7713    * @param str2 the second String, may be null
7714    * @return the portion of str2 where it differs from str1; returns the
7715    * empty String if they are equal
7716    * @see #indexOfDifference(CharSequence,CharSequence)
7717    * @since 2.0
7718    */
 
7719  9 toggle public static String difference(final String str1, final String str2) {
7720  9 if (str1 == null) {
7721  2 return str2;
7722    }
7723  7 if (str2 == null) {
7724  1 return str1;
7725    }
7726  6 final int at = indexOfDifference(str1, str2);
7727  6 if (at == INDEX_NOT_FOUND) {
7728  2 return EMPTY;
7729    }
7730  4 return str2.substring(at);
7731    }
7732   
7733    /**
7734    * <p>Compares two CharSequences, and returns the index at which the
7735    * CharSequences begin to differ.</p>
7736    *
7737    * <p>For example,
7738    * {@code indexOfDifference("i am a machine", "i am a robot") -> 7}</p>
7739    *
7740    * <pre>
7741    * StringUtils.indexOfDifference(null, null) = -1
7742    * StringUtils.indexOfDifference("", "") = -1
7743    * StringUtils.indexOfDifference("", "abc") = 0
7744    * StringUtils.indexOfDifference("abc", "") = 0
7745    * StringUtils.indexOfDifference("abc", "abc") = -1
7746    * StringUtils.indexOfDifference("ab", "abxyz") = 2
7747    * StringUtils.indexOfDifference("abcde", "abxyz") = 2
7748    * StringUtils.indexOfDifference("abcde", "xyz") = 0
7749    * </pre>
7750    *
7751    * @param cs1 the first CharSequence, may be null
7752    * @param cs2 the second CharSequence, may be null
7753    * @return the index where cs1 and cs2 begin to differ; -1 if they are equal
7754    * @since 2.0
7755    * @since 3.0 Changed signature from indexOfDifference(String, String) to
7756    * indexOfDifference(CharSequence, CharSequence)
7757    */
 
7758  15 toggle public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) {
7759  15 if (cs1 == cs2) {
7760  5 return INDEX_NOT_FOUND;
7761    }
7762  10 if (cs1 == null || cs2 == null) {
7763  2 return 0;
7764    }
7765  8 int i;
7766  22 for (i = 0; i < cs1.length() && i < cs2.length(); ++i) {
7767  18 if (cs1.charAt(i) != cs2.charAt(i)) {
7768  4 break;
7769    }
7770    }
7771  8 if (i < cs2.length() || i < cs1.length()) {
7772  8 return i;
7773    }
7774  0 return INDEX_NOT_FOUND;
7775    }
7776   
7777    /**
7778    * <p>Compares all CharSequences in an array and returns the index at which the
7779    * CharSequences begin to differ.</p>
7780    *
7781    * <p>For example,
7782    * <code>indexOfDifference(new String[] {"i am a machine", "i am a robot"}) -&gt; 7</code></p>
7783    *
7784    * <pre>
7785    * StringUtils.indexOfDifference(null) = -1
7786    * StringUtils.indexOfDifference(new String[] {}) = -1
7787    * StringUtils.indexOfDifference(new String[] {"abc"}) = -1
7788    * StringUtils.indexOfDifference(new String[] {null, null}) = -1
7789    * StringUtils.indexOfDifference(new String[] {"", ""}) = -1
7790    * StringUtils.indexOfDifference(new String[] {"", null}) = 0
7791    * StringUtils.indexOfDifference(new String[] {"abc", null, null}) = 0
7792    * StringUtils.indexOfDifference(new String[] {null, null, "abc"}) = 0
7793    * StringUtils.indexOfDifference(new String[] {"", "abc"}) = 0
7794    * StringUtils.indexOfDifference(new String[] {"abc", ""}) = 0
7795    * StringUtils.indexOfDifference(new String[] {"abc", "abc"}) = -1
7796    * StringUtils.indexOfDifference(new String[] {"abc", "a"}) = 1
7797    * StringUtils.indexOfDifference(new String[] {"ab", "abxyz"}) = 2
7798    * StringUtils.indexOfDifference(new String[] {"abcde", "abxyz"}) = 2
7799    * StringUtils.indexOfDifference(new String[] {"abcde", "xyz"}) = 0
7800    * StringUtils.indexOfDifference(new String[] {"xyz", "abcde"}) = 0
7801    * StringUtils.indexOfDifference(new String[] {"i am a machine", "i am a robot"}) = 7
7802    * </pre>
7803    *
7804    * @param css array of CharSequences, entries may be null
7805    * @return the index where the strings begin to differ; -1 if they are all equal
7806    * @since 2.4
7807    * @since 3.0 Changed signature from indexOfDifference(String...) to indexOfDifference(CharSequence...)
7808    */
 
7809  32 toggle public static int indexOfDifference(final CharSequence... css) {
7810  32 if (css == null || css.length <= 1) {
7811  4 return INDEX_NOT_FOUND;
7812    }
7813  28 boolean anyStringNull = false;
7814  28 boolean allStringsNull = true;
7815  28 final int arrayLen = css.length;
7816  28 int shortestStrLen = Integer.MAX_VALUE;
7817  28 int longestStrLen = 0;
7818   
7819    // find the min and max string lengths; this avoids checking to make
7820    // sure we are not exceeding the length of the string each time through
7821    // the bottom loop.
7822  28 for (CharSequence cs : css) {
7823  60 if (cs == null) {
7824  14 anyStringNull = true;
7825  14 shortestStrLen = 0;
7826    } else {
7827  46 allStringsNull = false;
7828  46 shortestStrLen = Math.min(cs.length(), shortestStrLen);
7829  46 longestStrLen = Math.max(cs.length(), longestStrLen);
7830    }
7831    }
7832   
7833    // handle lists containing all nulls or all empty strings
7834  28 if (allStringsNull || longestStrLen == 0 && !anyStringNull) {
7835  4 return INDEX_NOT_FOUND;
7836    }
7837   
7838    // handle lists containing some nulls or some empty strings
7839  24 if (shortestStrLen == 0) {
7840  10 return 0;
7841    }
7842   
7843    // find the position with the first difference across all strings
7844  14 int firstDiff = -1;
7845  44 for (int stringPos = 0; stringPos < shortestStrLen; stringPos++) {
7846  38 final char comparisonChar = css[0].charAt(stringPos);
7847  68 for (int arrayPos = 1; arrayPos < arrayLen; arrayPos++) {
7848  38 if (css[arrayPos].charAt(stringPos) != comparisonChar) {
7849  8 firstDiff = stringPos;
7850  8 break;
7851    }
7852    }
7853  38 if (firstDiff != -1) {
7854  8 break;
7855    }
7856    }
7857   
7858  14 if (firstDiff == -1 && shortestStrLen != longestStrLen) {
7859    // we compared all of the characters up to the length of the
7860    // shortest string and didn't find a match, but the string lengths
7861    // vary, so return the length of the shortest string.
7862  4 return shortestStrLen;
7863    }
7864  10 return firstDiff;
7865    }
7866   
7867    /**
7868    * <p>Compares all Strings in an array and returns the initial sequence of
7869    * characters that is common to all of them.</p>
7870    *
7871    * <p>For example,
7872    * <code>getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) -&gt; "i am a "</code></p>
7873    *
7874    * <pre>
7875    * StringUtils.getCommonPrefix(null) = ""
7876    * StringUtils.getCommonPrefix(new String[] {}) = ""
7877    * StringUtils.getCommonPrefix(new String[] {"abc"}) = "abc"
7878    * StringUtils.getCommonPrefix(new String[] {null, null}) = ""
7879    * StringUtils.getCommonPrefix(new String[] {"", ""}) = ""
7880    * StringUtils.getCommonPrefix(new String[] {"", null}) = ""
7881    * StringUtils.getCommonPrefix(new String[] {"abc", null, null}) = ""
7882    * StringUtils.getCommonPrefix(new String[] {null, null, "abc"}) = ""
7883    * StringUtils.getCommonPrefix(new String[] {"", "abc"}) = ""
7884    * StringUtils.getCommonPrefix(new String[] {"abc", ""}) = ""
7885    * StringUtils.getCommonPrefix(new String[] {"abc", "abc"}) = "abc"
7886    * StringUtils.getCommonPrefix(new String[] {"abc", "a"}) = "a"
7887    * StringUtils.getCommonPrefix(new String[] {"ab", "abxyz"}) = "ab"
7888    * StringUtils.getCommonPrefix(new String[] {"abcde", "abxyz"}) = "ab"
7889    * StringUtils.getCommonPrefix(new String[] {"abcde", "xyz"}) = ""
7890    * StringUtils.getCommonPrefix(new String[] {"xyz", "abcde"}) = ""
7891    * StringUtils.getCommonPrefix(new String[] {"i am a machine", "i am a robot"}) = "i am a "
7892    * </pre>
7893    *
7894    * @param strs array of String objects, entries may be null
7895    * @return the initial sequence of characters that are common to all Strings
7896    * in the array; empty String if the array is null, the elements are all null
7897    * or if there is no common prefix.
7898    * @since 2.4
7899    */
 
7900  17 toggle public static String getCommonPrefix(final String... strs) {
7901  17 if (strs == null || strs.length == 0) {
7902  2 return EMPTY;
7903    }
7904  15 final int smallestIndexOfDiff = indexOfDifference(strs);
7905  15 if (smallestIndexOfDiff == INDEX_NOT_FOUND) {
7906    // all strings were identical
7907  4 if (strs[0] == null) {
7908  1 return EMPTY;
7909    }
7910  3 return strs[0];
7911  11 } else if (smallestIndexOfDiff == 0) {
7912    // there were no common initial characters
7913  7 return EMPTY;
7914    } else {
7915    // we found a common initial character sequence
7916  4 return strs[0].substring(0, smallestIndexOfDiff);
7917    }
7918    }
7919   
7920    // Misc
7921    //-----------------------------------------------------------------------
7922    /**
7923    * <p>Find the Levenshtein distance between two Strings.</p>
7924    *
7925    * <p>This is the number of changes needed to change one String into
7926    * another, where each change is a single character modification (deletion,
7927    * insertion or substitution).</p>
7928    *
7929    * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
7930    * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
7931    * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
7932    *
7933    * <pre>
7934    * StringUtils.getLevenshteinDistance(null, *) = IllegalArgumentException
7935    * StringUtils.getLevenshteinDistance(*, null) = IllegalArgumentException
7936    * StringUtils.getLevenshteinDistance("","") = 0
7937    * StringUtils.getLevenshteinDistance("","a") = 1
7938    * StringUtils.getLevenshteinDistance("aaapppp", "") = 7
7939    * StringUtils.getLevenshteinDistance("frog", "fog") = 1
7940    * StringUtils.getLevenshteinDistance("fly", "ant") = 3
7941    * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
7942    * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
7943    * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
7944    * StringUtils.getLevenshteinDistance("hello", "hallo") = 1
7945    * </pre>
7946    *
7947    * @param s the first String, must not be null
7948    * @param t the second String, must not be null
7949    * @return result distance
7950    * @throws IllegalArgumentException if either String input {@code null}
7951    * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
7952    * getLevenshteinDistance(CharSequence, CharSequence)
7953    * @deprecated as of 3.6, use commons-text
7954    * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
7955    * LevenshteinDistance</a> instead
7956    */
 
7957  12 toggle @Deprecated
7958    public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
7959  12 if (s == null || t == null) {
7960  2 throw new IllegalArgumentException("Strings must not be null");
7961    }
7962   
7963  10 int n = s.length();
7964  10 int m = t.length();
7965   
7966  10 if (n == 0) {
7967  2 return m;
7968  8 } else if (m == 0) {
7969  1 return n;
7970    }
7971   
7972  7 if (n > m) {
7973    // swap the input strings to consume less memory
7974  3 final CharSequence tmp = s;
7975  3 s = t;
7976  3 t = tmp;
7977  3 n = m;
7978  3 m = t.length();
7979    }
7980   
7981  7 final int p[] = new int[n + 1];
7982    // indexes into strings s and t
7983  7 int i; // iterates through s
7984  7 int j; // iterates through t
7985  7 int upper_left;
7986  7 int upper;
7987   
7988  7 char t_j; // jth character of t
7989  7 int cost;
7990   
7991  45 for (i = 0; i <= n; i++) {
7992  38 p[i] = i;
7993    }
7994   
7995  51 for (j = 1; j <= m; j++) {
7996  44 upper_left = p[0];
7997  44 t_j = t.charAt(j - 1);
7998  44 p[0] = j;
7999   
8000  250 for (i = 1; i <= n; i++) {
8001  206 upper = p[i];
8002  206 cost = s.charAt(i - 1) == t_j ? 0 : 1;
8003    // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
8004  206 p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
8005  206 upper_left = upper;
8006    }
8007    }
8008   
8009  7 return p[n];
8010    }
8011   
8012    /**
8013    * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
8014    * threshold.</p>
8015    *
8016    * <p>This is the number of changes needed to change one String into
8017    * another, where each change is a single character modification (deletion,
8018    * insertion or substitution).</p>
8019    *
8020    * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
8021    * and Chas Emerick's implementation of the Levenshtein distance algorithm from
8022    * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
8023    *
8024    * <pre>
8025    * StringUtils.getLevenshteinDistance(null, *, *) = IllegalArgumentException
8026    * StringUtils.getLevenshteinDistance(*, null, *) = IllegalArgumentException
8027    * StringUtils.getLevenshteinDistance(*, *, -1) = IllegalArgumentException
8028    * StringUtils.getLevenshteinDistance("","", 0) = 0
8029    * StringUtils.getLevenshteinDistance("aaapppp", "", 8) = 7
8030    * StringUtils.getLevenshteinDistance("aaapppp", "", 7) = 7
8031    * StringUtils.getLevenshteinDistance("aaapppp", "", 6)) = -1
8032    * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
8033    * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
8034    * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
8035    * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
8036    * </pre>
8037    *
8038    * @param s the first String, must not be null
8039    * @param t the second String, must not be null
8040    * @param threshold the target threshold, must not be negative
8041    * @return result distance, or {@code -1} if the distance would be greater than the threshold
8042    * @throws IllegalArgumentException if either String input {@code null} or negative threshold
8043    * @deprecated as of 3.6, use commons-text
8044    * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/LevenshteinDistance.html">
8045    * LevenshteinDistance</a> instead
8046    */
 
8047  41 toggle @Deprecated
8048    public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) {
8049  41 if (s == null || t == null) {
8050  2 throw new IllegalArgumentException("Strings must not be null");
8051    }
8052  39 if (threshold < 0) {
8053  1 throw new IllegalArgumentException("Threshold must not be negative");
8054    }
8055   
8056    /*
8057    This implementation only computes the distance if it's less than or equal to the
8058    threshold value, returning -1 if it's greater. The advantage is performance: unbounded
8059    distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
8060    computing a diagonal stripe of width 2k + 1 of the cost table.
8061    It is also possible to use this to compute the unbounded Levenshtein distance by starting
8062    the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
8063    d is the distance.
8064   
8065    One subtlety comes from needing to ignore entries on the border of our stripe
8066    eg.
8067    p[] = |#|#|#|*
8068    d[] = *|#|#|#|
8069    We must ignore the entry to the left of the leftmost member
8070    We must ignore the entry above the rightmost member
8071   
8072    Another subtlety comes from our stripe running off the matrix if the strings aren't
8073    of the same size. Since string s is always swapped to be the shorter of the two,
8074    the stripe will always run off to the upper right instead of the lower left of the matrix.
8075   
8076    As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
8077    In this case we're going to walk a stripe of length 3. The matrix would look like so:
8078   
8079    1 2 3 4 5
8080    1 |#|#| | | |
8081    2 |#|#|#| | |
8082    3 | |#|#|#| |
8083    4 | | |#|#|#|
8084    5 | | | |#|#|
8085    6 | | | | |#|
8086    7 | | | | | |
8087   
8088    Note how the stripe leads off the table as there is no possible way to turn a string of length 5
8089    into one of length 7 in edit distance of 1.
8090   
8091    Additionally, this implementation decreases memory usage by using two
8092    single-dimensional arrays and swapping them back and forth instead of allocating
8093    an entire n by m matrix. This requires a few minor changes, such as immediately returning
8094    when it's detected that the stripe has run off the matrix and initially filling the arrays with
8095    large values so that entries we don't compute are ignored.
8096   
8097    See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
8098    */
8099   
8100  38 int n = s.length(); // length of s
8101  38 int m = t.length(); // length of t
8102   
8103    // if one string is empty, the edit distance is necessarily the length of the other
8104  38 if (n == 0) {
8105  1 return m <= threshold ? m : -1;
8106  37 } else if (m == 0) {
8107  3 return n <= threshold ? n : -1;
8108    }
8109    // no need to calculate the distance if the length difference is greater than the threshold
8110  34 else if (Math.abs(n - m) > threshold) {
8111  4 return -1;
8112    }
8113   
8114  30 if (n > m) {
8115    // swap the two strings to consume less memory
8116  12 final CharSequence tmp = s;
8117  12 s = t;
8118  12 t = tmp;
8119  12 n = m;
8120  12 m = t.length();
8121    }
8122   
8123  30 int p[] = new int[n + 1]; // 'previous' cost array, horizontally
8124  30 int d[] = new int[n + 1]; // cost array, horizontally
8125  30 int _d[]; // placeholder to assist in swapping p and d
8126   
8127    // fill in starting table values
8128  30 final int boundary = Math.min(n, threshold) + 1;
8129  141 for (int i = 0; i < boundary; i++) {
8130  111 p[i] = i;
8131    }
8132    // these fills ensure that the value above the rightmost entry of our
8133    // stripe will be ignored in following loop iterations
8134  30 Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
8135  30 Arrays.fill(d, Integer.MAX_VALUE);
8136   
8137    // iterates through t
8138  185 for (int j = 1; j <= m; j++) {
8139  155 final char t_j = t.charAt(j - 1); // jth character of t
8140  155 d[0] = j;
8141   
8142    // compute stripe indices, constrain to array size
8143  155 final int min = Math.max(1, j - threshold);
8144  155 final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(n, j + threshold);
8145   
8146    // the stripe may lead off of the table if s and t are of different sizes
8147  155 if (min > max) {
8148  0 return -1;
8149    }
8150   
8151    // ignore entry left of leftmost
8152  155 if (min > 1) {
8153  8 d[min - 1] = Integer.MAX_VALUE;
8154    }
8155   
8156    // iterates through [min, max] in s
8157  694 for (int i = min; i <= max; i++) {
8158  539 if (s.charAt(i - 1) == t_j) {
8159    // diagonally left and up
8160  42 d[i] = p[i - 1];
8161    } else {
8162    // 1 + minimum of cell to the left, to the top, diagonally left and up
8163  497 d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
8164    }
8165    }
8166   
8167    // copy current distance counts to 'previous row' distance counts
8168  155 _d = p;
8169  155 p = d;
8170  155 d = _d;
8171    }
8172   
8173    // if p[n] is greater than the threshold, there's no guarantee on it being the correct
8174    // distance
8175  30 if (p[n] <= threshold) {
8176  22 return p[n];
8177    }
8178  8 return -1;
8179    }
8180   
8181    /**
8182    * <p>Find the Jaro Winkler Distance which indicates the similarity score between two Strings.</p>
8183    *
8184    * <p>The Jaro measure is the weighted sum of percentage of matched characters from each file and transposed characters.
8185    * Winkler increased this measure for matching initial characters.</p>
8186    *
8187    * <p>This implementation is based on the Jaro Winkler similarity algorithm
8188    * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.</p>
8189    *
8190    * <pre>
8191    * StringUtils.getJaroWinklerDistance(null, null) = IllegalArgumentException
8192    * StringUtils.getJaroWinklerDistance("","") = 0.0
8193    * StringUtils.getJaroWinklerDistance("","a") = 0.0
8194    * StringUtils.getJaroWinklerDistance("aaapppp", "") = 0.0
8195    * StringUtils.getJaroWinklerDistance("frog", "fog") = 0.93
8196    * StringUtils.getJaroWinklerDistance("fly", "ant") = 0.0
8197    * StringUtils.getJaroWinklerDistance("elephant", "hippo") = 0.44
8198    * StringUtils.getJaroWinklerDistance("hippo", "elephant") = 0.44
8199    * StringUtils.getJaroWinklerDistance("hippo", "zzzzzzzz") = 0.0
8200    * StringUtils.getJaroWinklerDistance("hello", "hallo") = 0.88
8201    * StringUtils.getJaroWinklerDistance("ABC Corporation", "ABC Corp") = 0.93
8202    * StringUtils.getJaroWinklerDistance("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
8203    * StringUtils.getJaroWinklerDistance("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
8204    * StringUtils.getJaroWinklerDistance("PENNSYLVANIA", "PENNCISYLVNIA") = 0.88
8205    * </pre>
8206    *
8207    * @param first the first String, must not be null
8208    * @param second the second String, must not be null
8209    * @return result distance
8210    * @throws IllegalArgumentException if either String input {@code null}
8211    * @since 3.3
8212    * @deprecated as of 3.6, use commons-text
8213    * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/JaroWinklerDistance.html">
8214    * JaroWinklerDistance</a> instead
8215    */
 
8216  12 toggle @Deprecated
8217    public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
8218  12 final double DEFAULT_SCALING_FACTOR = 0.1;
8219   
8220  12 if (first == null || second == null) {
8221  3 throw new IllegalArgumentException("Strings must not be null");
8222    }
8223   
8224  9 final int[] mtp = matches(first, second);
8225  9 final double m = mtp[0];
8226  9 if (m == 0) {
8227  1 return 0D;
8228    }
8229  8 final double j = ((m / first.length() + m / second.length() + (m - mtp[1]) / m)) / 3;
8230  8 final double jw = j < 0.7D ? j : j + Math.min(DEFAULT_SCALING_FACTOR, 1D / mtp[3]) * mtp[2] * (1D - j);
8231  8 return Math.round(jw * 100.0D) / 100.0D;
8232    }
8233   
 
8234  9 toggle private static int[] matches(final CharSequence first, final CharSequence second) {
8235  9 CharSequence max, min;
8236  9 if (first.length() > second.length()) {
8237  5 max = first;
8238  5 min = second;
8239    } else {
8240  4 max = second;
8241  4 min = first;
8242    }
8243  9 final int range = Math.max(max.length() / 2 - 1, 0);
8244  9 final int[] matchIndexes = new int[min.length()];
8245  9 Arrays.fill(matchIndexes, -1);
8246  9 final boolean[] matchFlags = new boolean[max.length()];
8247  9 int matches = 0;
8248  104 for (int mi = 0; mi < min.length(); mi++) {
8249  95 final char c1 = min.charAt(mi);
8250  703 for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
8251  688 if (!matchFlags[xi] && c1 == max.charAt(xi)) {
8252  80 matchIndexes[mi] = xi;
8253  80 matchFlags[xi] = true;
8254  80 matches++;
8255  80 break;
8256    }
8257    }
8258    }
8259  9 final char[] ms1 = new char[matches];
8260  9 final char[] ms2 = new char[matches];
8261  104 for (int i = 0, si = 0; i < min.length(); i++) {
8262  95 if (matchIndexes[i] != -1) {
8263  80 ms1[si] = min.charAt(i);
8264  80 si++;
8265    }
8266    }
8267  127 for (int i = 0, si = 0; i < max.length(); i++) {
8268  118 if (matchFlags[i]) {
8269  80 ms2[si] = max.charAt(i);
8270  80 si++;
8271    }
8272    }
8273  9 int transpositions = 0;
8274  89 for (int mi = 0; mi < ms1.length; mi++) {
8275  80 if (ms1[mi] != ms2[mi]) {
8276  15 transpositions++;
8277    }
8278    }
8279  9 int prefix = 0;
8280  31 for (int mi = 0; mi < min.length(); mi++) {
8281  30 if (first.charAt(mi) == second.charAt(mi)) {
8282  22 prefix++;
8283    } else {
8284  8 break;
8285    }
8286    }
8287  9 return new int[] { matches, transpositions / 2, prefix, max.length() };
8288    }
8289   
8290    /**
8291    * <p>Find the Fuzzy Distance which indicates the similarity score between two Strings.</p>
8292    *
8293    * <p>This string matching algorithm is similar to the algorithms of editors such as Sublime Text,
8294    * TextMate, Atom and others. One point is given for every matched character. Subsequent
8295    * matches yield two bonus points. A higher score indicates a higher similarity.</p>
8296    *
8297    * <pre>
8298    * StringUtils.getFuzzyDistance(null, null, null) = IllegalArgumentException
8299    * StringUtils.getFuzzyDistance("", "", Locale.ENGLISH) = 0
8300    * StringUtils.getFuzzyDistance("Workshop", "b", Locale.ENGLISH) = 0
8301    * StringUtils.getFuzzyDistance("Room", "o", Locale.ENGLISH) = 1
8302    * StringUtils.getFuzzyDistance("Workshop", "w", Locale.ENGLISH) = 1
8303    * StringUtils.getFuzzyDistance("Workshop", "ws", Locale.ENGLISH) = 2
8304    * StringUtils.getFuzzyDistance("Workshop", "wo", Locale.ENGLISH) = 4
8305    * StringUtils.getFuzzyDistance("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
8306    * </pre>
8307    *
8308    * @param term a full term that should be matched against, must not be null
8309    * @param query the query that will be matched against a term, must not be null
8310    * @param locale This string matching logic is case insensitive. A locale is necessary to normalize
8311    * both Strings to lower case.
8312    * @return result score
8313    * @throws IllegalArgumentException if either String input {@code null} or Locale input {@code null}
8314    * @since 3.4
8315    * @deprecated as of 3.6, use commons-text
8316    * <a href="https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/similarity/FuzzyScore.html">
8317    * FuzzyScore</a> instead
8318    */
 
8319  11 toggle @Deprecated
8320    public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) {
8321  11 if (term == null || query == null) {
8322  3 throw new IllegalArgumentException("Strings must not be null");
8323  8 } else if (locale == null) {
8324  1 throw new IllegalArgumentException("Locale must not be null");
8325    }
8326   
8327    // fuzzy logic is case insensitive. We normalize the Strings to lower
8328    // case right from the start. Turning characters to lower case
8329    // via Character.toLowerCase(char) is unfortunately insufficient
8330    // as it does not accept a locale.
8331  7 final String termLowerCase = term.toString().toLowerCase(locale);
8332  7 final String queryLowerCase = query.toString().toLowerCase(locale);
8333   
8334    // the resulting score
8335  7 int score = 0;
8336   
8337    // the position in the term which will be scanned next for potential
8338    // query character matches
8339  7 int termIndex = 0;
8340   
8341    // index of the previously matched character in the term
8342  7 int previousMatchingCharacterIndex = Integer.MIN_VALUE;
8343   
8344  17 for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
8345  10 final char queryChar = queryLowerCase.charAt(queryIndex);
8346   
8347  10 boolean termCharacterMatchFound = false;
8348  38 for (; termIndex < termLowerCase.length() && !termCharacterMatchFound; termIndex++) {
8349  28 final char termChar = termLowerCase.charAt(termIndex);
8350   
8351  28 if (queryChar == termChar) {
8352    // simple character matches result in one point
8353  9 score++;
8354   
8355    // subsequent character matches further improve
8356    // the score.
8357  9 if (previousMatchingCharacterIndex + 1 == termIndex) {
8358  1 score += 2;
8359    }
8360   
8361  9 previousMatchingCharacterIndex = termIndex;
8362   
8363    // we can leave the nested loop. Every character in the
8364    // query can match at most one character in the term.
8365  9 termCharacterMatchFound = true;
8366    }
8367    }
8368    }
8369   
8370  7 return score;
8371    }
8372   
8373    // startsWith
8374    //-----------------------------------------------------------------------
8375   
8376    /**
8377    * <p>Check if a CharSequence starts with a specified prefix.</p>
8378    *
8379    * <p>{@code null}s are handled without exceptions. Two {@code null}
8380    * references are considered to be equal. The comparison is case sensitive.</p>
8381    *
8382    * <pre>
8383    * StringUtils.startsWith(null, null) = true
8384    * StringUtils.startsWith(null, "abc") = false
8385    * StringUtils.startsWith("abcdef", null) = false
8386    * StringUtils.startsWith("abcdef", "abc") = true
8387    * StringUtils.startsWith("ABCDEF", "abc") = false
8388    * </pre>
8389    *
8390    * @see java.lang.String#startsWith(String)
8391    * @param str the CharSequence to check, may be null
8392    * @param prefix the prefix to find, may be null
8393    * @return {@code true} if the CharSequence starts with the prefix, case sensitive, or
8394    * both {@code null}
8395    * @since 2.4
8396    * @since 3.0 Changed signature from startsWith(String, String) to startsWith(CharSequence, CharSequence)
8397    */
 
8398  42 toggle public static boolean startsWith(final CharSequence str, final CharSequence prefix) {
8399  42 return startsWith(str, prefix, false);
8400    }
8401   
8402    /**
8403    * <p>Case insensitive check if a CharSequence starts with a specified prefix.</p>
8404    *
8405    * <p>{@code null}s are handled without exceptions. Two {@code null}
8406    * references are considered to be equal. The comparison is case insensitive.</p>
8407    *
8408    * <pre>
8409    * StringUtils.startsWithIgnoreCase(null, null) = true
8410    * StringUtils.startsWithIgnoreCase(null, "abc") = false
8411    * StringUtils.startsWithIgnoreCase("abcdef", null) = false
8412    * StringUtils.startsWithIgnoreCase("abcdef", "abc") = true
8413    * StringUtils.startsWithIgnoreCase("ABCDEF", "abc") = true
8414    * </pre>
8415    *
8416    * @see java.lang.String#startsWith(String)
8417    * @param str the CharSequence to check, may be null
8418    * @param prefix the prefix to find, may be null
8419    * @return {@code true} if the CharSequence starts with the prefix, case insensitive, or
8420    * both {@code null}
8421    * @since 2.4
8422    * @since 3.0 Changed signature from startsWithIgnoreCase(String, String) to startsWithIgnoreCase(CharSequence, CharSequence)
8423    */
 
8424  17 toggle public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) {
8425  17 return startsWith(str, prefix, true);
8426    }
8427   
8428    /**
8429    * <p>Check if a CharSequence starts with a specified prefix (optionally case insensitive).</p>
8430    *
8431    * @see java.lang.String#startsWith(String)
8432    * @param str the CharSequence to check, may be null
8433    * @param prefix the prefix to find, may be null
8434    * @param ignoreCase indicates whether the compare should ignore case
8435    * (case insensitive) or not.
8436    * @return {@code true} if the CharSequence starts with the prefix or
8437    * both {@code null}
8438    */
 
8439  94 toggle private static boolean startsWith(final CharSequence str, final CharSequence prefix, final boolean ignoreCase) {
8440  94 if (str == null || prefix == null) {
8441  12 return str == null && prefix == null;
8442    }
8443  82 if (prefix.length() > str.length()) {
8444  8 return false;
8445    }
8446  74 return CharSequenceUtils.regionMatches(str, ignoreCase, 0, prefix, 0, prefix.length());
8447    }
8448   
8449    /**
8450    * <p>Check if a CharSequence starts with any of the provided case-sensitive prefixes.</p>
8451    *
8452    * <pre>
8453    * StringUtils.startsWithAny(null, null) = false
8454    * StringUtils.startsWithAny(null, new String[] {"abc"}) = false
8455    * StringUtils.startsWithAny("abcxyz", null) = false
8456    * StringUtils.startsWithAny("abcxyz", new String[] {""}) = true
8457    * StringUtils.startsWithAny("abcxyz", new String[] {"abc"}) = true
8458    * StringUtils.startsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8459    * StringUtils.startsWithAny("abcxyz", null, "xyz", "ABCX") = false
8460    * StringUtils.startsWithAny("ABCXYZ", null, "xyz", "abc") = false
8461    * </pre>
8462    *
8463    * @param sequence the CharSequence to check, may be null
8464    * @param searchStrings the case-sensitive CharSequence prefixes, may be empty or contain {@code null}
8465    * @see StringUtils#startsWith(CharSequence, CharSequence)
8466    * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8467    * the input {@code sequence} begins with any of the provided case-sensitive {@code searchStrings}.
8468    * @since 2.5
8469    * @since 3.0 Changed signature from startsWithAny(String, String[]) to startsWithAny(CharSequence, CharSequence...)
8470    */
 
8471  12 toggle public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8472  12 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8473  4 return false;
8474    }
8475  8 for (final CharSequence searchString : searchStrings) {
8476  18 if (startsWith(sequence, searchString)) {
8477  5 return true;
8478    }
8479    }
8480  3 return false;
8481    }
8482   
8483    // endsWith
8484    //-----------------------------------------------------------------------
8485   
8486    /**
8487    * <p>Check if a CharSequence ends with a specified suffix.</p>
8488    *
8489    * <p>{@code null}s are handled without exceptions. Two {@code null}
8490    * references are considered to be equal. The comparison is case sensitive.</p>
8491    *
8492    * <pre>
8493    * StringUtils.endsWith(null, null) = true
8494    * StringUtils.endsWith(null, "def") = false
8495    * StringUtils.endsWith("abcdef", null) = false
8496    * StringUtils.endsWith("abcdef", "def") = true
8497    * StringUtils.endsWith("ABCDEF", "def") = false
8498    * StringUtils.endsWith("ABCDEF", "cde") = false
8499    * StringUtils.endsWith("ABCDEF", "") = true
8500    * </pre>
8501    *
8502    * @see java.lang.String#endsWith(String)
8503    * @param str the CharSequence to check, may be null
8504    * @param suffix the suffix to find, may be null
8505    * @return {@code true} if the CharSequence ends with the suffix, case sensitive, or
8506    * both {@code null}
8507    * @since 2.4
8508    * @since 3.0 Changed signature from endsWith(String, String) to endsWith(CharSequence, CharSequence)
8509    */
 
8510  45 toggle public static boolean endsWith(final CharSequence str, final CharSequence suffix) {
8511  45 return endsWith(str, suffix, false);
8512    }
8513   
8514    /**
8515    * <p>Case insensitive check if a CharSequence ends with a specified suffix.</p>
8516    *
8517    * <p>{@code null}s are handled without exceptions. Two {@code null}
8518    * references are considered to be equal. The comparison is case insensitive.</p>
8519    *
8520    * <pre>
8521    * StringUtils.endsWithIgnoreCase(null, null) = true
8522    * StringUtils.endsWithIgnoreCase(null, "def") = false
8523    * StringUtils.endsWithIgnoreCase("abcdef", null) = false
8524    * StringUtils.endsWithIgnoreCase("abcdef", "def") = true
8525    * StringUtils.endsWithIgnoreCase("ABCDEF", "def") = true
8526    * StringUtils.endsWithIgnoreCase("ABCDEF", "cde") = false
8527    * </pre>
8528    *
8529    * @see java.lang.String#endsWith(String)
8530    * @param str the CharSequence to check, may be null
8531    * @param suffix the suffix to find, may be null
8532    * @return {@code true} if the CharSequence ends with the suffix, case insensitive, or
8533    * both {@code null}
8534    * @since 2.4
8535    * @since 3.0 Changed signature from endsWithIgnoreCase(String, String) to endsWithIgnoreCase(CharSequence, CharSequence)
8536    */
 
8537  24 toggle public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) {
8538  24 return endsWith(str, suffix, true);
8539    }
8540   
8541    /**
8542    * <p>Check if a CharSequence ends with a specified suffix (optionally case insensitive).</p>
8543    *
8544    * @see java.lang.String#endsWith(String)
8545    * @param str the CharSequence to check, may be null
8546    * @param suffix the suffix to find, may be null
8547    * @param ignoreCase indicates whether the compare should ignore case
8548    * (case insensitive) or not.
8549    * @return {@code true} if the CharSequence starts with the prefix or
8550    * both {@code null}
8551    */
 
8552  104 toggle private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) {
8553  104 if (str == null || suffix == null) {
8554  12 return str == null && suffix == null;
8555    }
8556  92 if (suffix.length() > str.length()) {
8557  8 return false;
8558    }
8559  84 final int strOffset = str.length() - suffix.length();
8560  84 return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length());
8561    }
8562   
8563    /**
8564    * <p>
8565    * Similar to <a
8566    * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize
8567    * -space</a>
8568    * </p>
8569    * <p>
8570    * The function returns the argument string with whitespace normalized by using
8571    * <code>{@link #trim(String)}</code> to remove leading and trailing whitespace
8572    * and then replacing sequences of whitespace characters by a single space.
8573    * </p>
8574    * In XML Whitespace characters are the same as those allowed by the <a
8575    * href="http://www.w3.org/TR/REC-xml/#NT-S">S</a> production, which is S ::= (#x20 | #x9 | #xD | #xA)+
8576    * <p>
8577    * Java's regexp pattern \s defines whitespace as [ \t\n\x0B\f\r]
8578    *
8579    * <p>For reference:</p>
8580    * <ul>
8581    * <li>\x0B = vertical tab</li>
8582    * <li>\f = #xC = form feed</li>
8583    * <li>#x20 = space</li>
8584    * <li>#x9 = \t</li>
8585    * <li>#xA = \n</li>
8586    * <li>#xD = \r</li>
8587    * </ul>
8588    *
8589    * <p>
8590    * The difference is that Java's whitespace includes vertical tab and form feed, which this functional will also
8591    * normalize. Additionally <code>{@link #trim(String)}</code> removes control characters (char &lt;= 32) from both
8592    * ends of this String.
8593    * </p>
8594    *
8595    * @see Pattern
8596    * @see #trim(String)
8597    * @see <a
8598    * href="http://www.w3.org/TR/xpath/#function-normalize-space">http://www.w3.org/TR/xpath/#function-normalize-space</a>
8599    * @param str the source String to normalize whitespaces from, may be null
8600    * @return the modified string with whitespace normalized, {@code null} if null String input
8601    *
8602    * @since 3.0
8603    */
 
8604  20 toggle public static String normalizeSpace(final String str) {
8605    // LANG-1020: Improved performance significantly by normalizing manually instead of using regex
8606    // See https://github.com/librucha/commons-lang-normalizespaces-benchmark for performance test
8607  20 if (isEmpty(str)) {
8608  2 return str;
8609    }
8610  18 final int size = str.length();
8611  18 final char[] newChars = new char[size];
8612  18 int count = 0;
8613  18 int whitespacesCount = 0;
8614  18 boolean startWhitespaces = true;
8615  79 for (int i = 0; i < size; i++) {
8616  61 final char actualChar = str.charAt(i);
8617  61 final boolean isWhitespace = Character.isWhitespace(actualChar);
8618  61 if (!isWhitespace) {
8619  16 startWhitespaces = false;
8620  16 newChars[count++] = (actualChar == 160 ? 32 : actualChar);
8621  16 whitespacesCount = 0;
8622    } else {
8623  45 if (whitespacesCount == 0 && !startWhitespaces) {
8624  10 newChars[count++] = SPACE.charAt(0);
8625    }
8626  45 whitespacesCount++;
8627    }
8628    }
8629  18 if (startWhitespaces) {
8630  12 return EMPTY;
8631    }
8632  6 return new String(newChars, 0, count - (whitespacesCount > 0 ? 1 : 0)).trim();
8633    }
8634   
8635    /**
8636    * <p>Check if a CharSequence ends with any of the provided case-sensitive suffixes.</p>
8637    *
8638    * <pre>
8639    * StringUtils.endsWithAny(null, null) = false
8640    * StringUtils.endsWithAny(null, new String[] {"abc"}) = false
8641    * StringUtils.endsWithAny("abcxyz", null) = false
8642    * StringUtils.endsWithAny("abcxyz", new String[] {""}) = true
8643    * StringUtils.endsWithAny("abcxyz", new String[] {"xyz"}) = true
8644    * StringUtils.endsWithAny("abcxyz", new String[] {null, "xyz", "abc"}) = true
8645    * StringUtils.endsWithAny("abcXYZ", "def", "XYZ") = true
8646    * StringUtils.endsWithAny("abcXYZ", "def", "xyz") = false
8647    * </pre>
8648    *
8649    * @param sequence the CharSequence to check, may be null
8650    * @param searchStrings the case-sensitive CharSequences to find, may be empty or contain {@code null}
8651    * @see StringUtils#endsWith(CharSequence, CharSequence)
8652    * @return {@code true} if the input {@code sequence} is {@code null} AND no {@code searchStrings} are provided, or
8653    * the input {@code sequence} ends in any of the provided case-sensitive {@code searchStrings}.
8654    * @since 3.0
8655    */
 
8656  15 toggle public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) {
8657  15 if (isEmpty(sequence) || ArrayUtils.isEmpty(searchStrings)) {
8658  3 return false;
8659    }
8660  12 for (final CharSequence searchString : searchStrings) {
8661  20 if (endsWith(sequence, searchString)) {
8662  8 return true;
8663    }
8664    }
8665  4 return false;
8666    }
8667   
8668    /**
8669    * Appends the suffix to the end of the string if the string does not
8670    * already end with the suffix.
8671    *
8672    * @param str The string.
8673    * @param suffix The suffix to append to the end of the string.
8674    * @param ignoreCase Indicates whether the compare should ignore case.
8675    * @param suffixes Additional suffixes that are valid terminators (optional).
8676    *
8677    * @return A new String if suffix was appended, the same string otherwise.
8678    */
 
8679  32 toggle private static String appendIfMissing(final String str, final CharSequence suffix, final boolean ignoreCase, final CharSequence... suffixes) {
8680  32 if (str == null || isEmpty(suffix) || endsWith(str, suffix, ignoreCase)) {
8681  14 return str;
8682    }
8683  18 if (suffixes != null && suffixes.length > 0) {
8684  11 for (final CharSequence s : suffixes) {
8685  11 if (endsWith(str, s, ignoreCase)) {
8686  5 return str;
8687    }
8688    }
8689    }
8690  13 return str + suffix.toString();
8691    }
8692   
8693    /**
8694    * Appends the suffix to the end of the string if the string does not
8695    * already end with any of the suffixes.
8696    *
8697    * <pre>
8698    * StringUtils.appendIfMissing(null, null) = null
8699    * StringUtils.appendIfMissing("abc", null) = "abc"
8700    * StringUtils.appendIfMissing("", "xyz") = "xyz"
8701    * StringUtils.appendIfMissing("abc", "xyz") = "abcxyz"
8702    * StringUtils.appendIfMissing("abcxyz", "xyz") = "abcxyz"
8703    * StringUtils.appendIfMissing("abcXYZ", "xyz") = "abcXYZxyz"
8704    * </pre>
8705    * <p>With additional suffixes,</p>
8706    * <pre>
8707    * StringUtils.appendIfMissing(null, null, null) = null
8708    * StringUtils.appendIfMissing("abc", null, null) = "abc"
8709    * StringUtils.appendIfMissing("", "xyz", null) = "xyz"
8710    * StringUtils.appendIfMissing("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8711    * StringUtils.appendIfMissing("abc", "xyz", "") = "abc"
8712    * StringUtils.appendIfMissing("abc", "xyz", "mno") = "abcxyz"
8713    * StringUtils.appendIfMissing("abcxyz", "xyz", "mno") = "abcxyz"
8714    * StringUtils.appendIfMissing("abcmno", "xyz", "mno") = "abcmno"
8715    * StringUtils.appendIfMissing("abcXYZ", "xyz", "mno") = "abcXYZxyz"
8716    * StringUtils.appendIfMissing("abcMNO", "xyz", "mno") = "abcMNOxyz"
8717    * </pre>
8718    *
8719    * @param str The string.
8720    * @param suffix The suffix to append to the end of the string.
8721    * @param suffixes Additional suffixes that are valid terminators.
8722    *
8723    * @return A new String if suffix was appended, the same string otherwise.
8724    *
8725    * @since 3.2
8726    */
 
8727  16 toggle public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8728  16 return appendIfMissing(str, suffix, false, suffixes);
8729    }
8730   
8731    /**
8732    * Appends the suffix to the end of the string if the string does not
8733    * already end, case insensitive, with any of the suffixes.
8734    *
8735    * <pre>
8736    * StringUtils.appendIfMissingIgnoreCase(null, null) = null
8737    * StringUtils.appendIfMissingIgnoreCase("abc", null) = "abc"
8738    * StringUtils.appendIfMissingIgnoreCase("", "xyz") = "xyz"
8739    * StringUtils.appendIfMissingIgnoreCase("abc", "xyz") = "abcxyz"
8740    * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz") = "abcxyz"
8741    * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz") = "abcXYZ"
8742    * </pre>
8743    * <p>With additional suffixes,</p>
8744    * <pre>
8745    * StringUtils.appendIfMissingIgnoreCase(null, null, null) = null
8746    * StringUtils.appendIfMissingIgnoreCase("abc", null, null) = "abc"
8747    * StringUtils.appendIfMissingIgnoreCase("", "xyz", null) = "xyz"
8748    * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "abcxyz"
8749    * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8750    * StringUtils.appendIfMissingIgnoreCase("abc", "xyz", "mno") = "axyz"
8751    * StringUtils.appendIfMissingIgnoreCase("abcxyz", "xyz", "mno") = "abcxyz"
8752    * StringUtils.appendIfMissingIgnoreCase("abcmno", "xyz", "mno") = "abcmno"
8753    * StringUtils.appendIfMissingIgnoreCase("abcXYZ", "xyz", "mno") = "abcXYZ"
8754    * StringUtils.appendIfMissingIgnoreCase("abcMNO", "xyz", "mno") = "abcMNO"
8755    * </pre>
8756    *
8757    * @param str The string.
8758    * @param suffix The suffix to append to the end of the string.
8759    * @param suffixes Additional suffixes that are valid terminators.
8760    *
8761    * @return A new String if suffix was appended, the same string otherwise.
8762    *
8763    * @since 3.2
8764    */
 
8765  16 toggle public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) {
8766  16 return appendIfMissing(str, suffix, true, suffixes);
8767    }
8768   
8769    /**
8770    * Prepends the prefix to the start of the string if the string does not
8771    * already start with any of the prefixes.
8772    *
8773    * @param str The string.
8774    * @param prefix The prefix to prepend to the start of the string.
8775    * @param ignoreCase Indicates whether the compare should ignore case.
8776    * @param prefixes Additional prefixes that are valid (optional).
8777    *
8778    * @return A new String if prefix was prepended, the same string otherwise.
8779    */
 
8780  32 toggle private static String prependIfMissing(final String str, final CharSequence prefix, final boolean ignoreCase, final CharSequence... prefixes) {
8781  32 if (str == null || isEmpty(prefix) || startsWith(str, prefix, ignoreCase)) {
8782  14 return str;
8783    }
8784  18 if (prefixes != null && prefixes.length > 0) {
8785  11 for (final CharSequence p : prefixes) {
8786  11 if (startsWith(str, p, ignoreCase)) {
8787  5 return str;
8788    }
8789    }
8790    }
8791  13 return prefix.toString() + str;
8792    }
8793   
8794    /**
8795    * Prepends the prefix to the start of the string if the string does not
8796    * already start with any of the prefixes.
8797    *
8798    * <pre>
8799    * StringUtils.prependIfMissing(null, null) = null
8800    * StringUtils.prependIfMissing("abc", null) = "abc"
8801    * StringUtils.prependIfMissing("", "xyz") = "xyz"
8802    * StringUtils.prependIfMissing("abc", "xyz") = "xyzabc"
8803    * StringUtils.prependIfMissing("xyzabc", "xyz") = "xyzabc"
8804    * StringUtils.prependIfMissing("XYZabc", "xyz") = "xyzXYZabc"
8805    * </pre>
8806    * <p>With additional prefixes,</p>
8807    * <pre>
8808    * StringUtils.prependIfMissing(null, null, null) = null
8809    * StringUtils.prependIfMissing("abc", null, null) = "abc"
8810    * StringUtils.prependIfMissing("", "xyz", null) = "xyz"
8811    * StringUtils.prependIfMissing("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8812    * StringUtils.prependIfMissing("abc", "xyz", "") = "abc"
8813    * StringUtils.prependIfMissing("abc", "xyz", "mno") = "xyzabc"
8814    * StringUtils.prependIfMissing("xyzabc", "xyz", "mno") = "xyzabc"
8815    * StringUtils.prependIfMissing("mnoabc", "xyz", "mno") = "mnoabc"
8816    * StringUtils.prependIfMissing("XYZabc", "xyz", "mno") = "xyzXYZabc"
8817    * StringUtils.prependIfMissing("MNOabc", "xyz", "mno") = "xyzMNOabc"
8818    * </pre>
8819    *
8820    * @param str The string.
8821    * @param prefix The prefix to prepend to the start of the string.
8822    * @param prefixes Additional prefixes that are valid.
8823    *
8824    * @return A new String if prefix was prepended, the same string otherwise.
8825    *
8826    * @since 3.2
8827    */
 
8828  16 toggle public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8829  16 return prependIfMissing(str, prefix, false, prefixes);
8830    }
8831   
8832    /**
8833    * Prepends the prefix to the start of the string if the string does not
8834    * already start, case insensitive, with any of the prefixes.
8835    *
8836    * <pre>
8837    * StringUtils.prependIfMissingIgnoreCase(null, null) = null
8838    * StringUtils.prependIfMissingIgnoreCase("abc", null) = "abc"
8839    * StringUtils.prependIfMissingIgnoreCase("", "xyz") = "xyz"
8840    * StringUtils.prependIfMissingIgnoreCase("abc", "xyz") = "xyzabc"
8841    * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz") = "xyzabc"
8842    * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz") = "XYZabc"
8843    * </pre>
8844    * <p>With additional prefixes,</p>
8845    * <pre>
8846    * StringUtils.prependIfMissingIgnoreCase(null, null, null) = null
8847    * StringUtils.prependIfMissingIgnoreCase("abc", null, null) = "abc"
8848    * StringUtils.prependIfMissingIgnoreCase("", "xyz", null) = "xyz"
8849    * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", new CharSequence[]{null}) = "xyzabc"
8850    * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "") = "abc"
8851    * StringUtils.prependIfMissingIgnoreCase("abc", "xyz", "mno") = "xyzabc"
8852    * StringUtils.prependIfMissingIgnoreCase("xyzabc", "xyz", "mno") = "xyzabc"
8853    * StringUtils.prependIfMissingIgnoreCase("mnoabc", "xyz", "mno") = "mnoabc"
8854    * StringUtils.prependIfMissingIgnoreCase("XYZabc", "xyz", "mno") = "XYZabc"
8855    * StringUtils.prependIfMissingIgnoreCase("MNOabc", "xyz", "mno") = "MNOabc"
8856    * </pre>
8857    *
8858    * @param str The string.
8859    * @param prefix The prefix to prepend to the start of the string.
8860    * @param prefixes Additional prefixes that are valid (optional).
8861    *
8862    * @return A new String if prefix was prepended, the same string otherwise.
8863    *
8864    * @since 3.2
8865    */
 
8866  16 toggle public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) {
8867  16 return prependIfMissing(str, prefix, true, prefixes);
8868    }
8869   
8870    /**
8871    * Converts a <code>byte[]</code> to a String using the specified character encoding.
8872    *
8873    * @param bytes
8874    * the byte array to read from
8875    * @param charsetName
8876    * the encoding to use, if null then use the platform default
8877    * @return a new String
8878    * @throws UnsupportedEncodingException
8879    * If the named charset is not supported
8880    * @throws NullPointerException
8881    * if the input is null
8882    * @deprecated use {@link StringUtils#toEncodedString(byte[], Charset)} instead of String constants in your code
8883    * @since 3.1
8884    */
 
8885  3 toggle @Deprecated
8886    public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException {
8887  3 return charsetName != null ? new String(bytes, charsetName) : new String(bytes, Charset.defaultCharset());
8888    }
8889   
8890    /**
8891    * Converts a <code>byte[]</code> to a String using the specified character encoding.
8892    *
8893    * @param bytes
8894    * the byte array to read from
8895    * @param charset
8896    * the encoding to use, if null then use the platform default
8897    * @return a new String
8898    * @throws NullPointerException
8899    * if {@code bytes} is null
8900    * @since 3.2
8901    * @since 3.3 No longer throws {@link UnsupportedEncodingException}.
8902    */
 
8903  3 toggle public static String toEncodedString(final byte[] bytes, final Charset charset) {
8904  3 return new String(bytes, charset != null ? charset : Charset.defaultCharset());
8905    }
8906   
8907    /**
8908    * <p>
8909    * Wraps a string with a char.
8910    * </p>
8911    *
8912    * <pre>
8913    * StringUtils.wrap(null, *) = null
8914    * StringUtils.wrap("", *) = ""
8915    * StringUtils.wrap("ab", '\0') = "ab"
8916    * StringUtils.wrap("ab", 'x') = "xabx"
8917    * StringUtils.wrap("ab", '\'') = "'ab'"
8918    * StringUtils.wrap("\"ab\"", '\"') = "\"\"ab\"\""
8919    * </pre>
8920    *
8921    * @param str
8922    * the string to be wrapped, may be {@code null}
8923    * @param wrapWith
8924    * the char that will wrap {@code str}
8925    * @return the wrapped string, or {@code null} if {@code str==null}
8926    * @since 3.4
8927    */
 
8928  10 toggle public static String wrap(final String str, final char wrapWith) {
8929   
8930  10 if (isEmpty(str) || wrapWith == '\0') {
8931  3 return str;
8932    }
8933   
8934  7 return wrapWith + str + wrapWith;
8935    }
8936   
8937    /**
8938    * <p>
8939    * Wraps a String with another String.
8940    * </p>
8941    *
8942    * <p>
8943    * A {@code null} input String returns {@code null}.
8944    * </p>
8945    *
8946    * <pre>
8947    * StringUtils.wrap(null, *) = null
8948    * StringUtils.wrap("", *) = ""
8949    * StringUtils.wrap("ab", null) = "ab"
8950    * StringUtils.wrap("ab", "x") = "xabx"
8951    * StringUtils.wrap("ab", "\"") = "\"ab\""
8952    * StringUtils.wrap("\"ab\"", "\"") = "\"\"ab\"\""
8953    * StringUtils.wrap("ab", "'") = "'ab'"
8954    * StringUtils.wrap("'abcd'", "'") = "''abcd''"
8955    * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
8956    * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\""
8957    * </pre>
8958    *
8959    * @param str
8960    * the String to be wrapper, may be null
8961    * @param wrapWith
8962    * the String that will wrap str
8963    * @return wrapped String, {@code null} if null String input
8964    * @since 3.4
8965    */
 
8966  13 toggle public static String wrap(final String str, final String wrapWith) {
8967   
8968  13 if (isEmpty(str) || isEmpty(wrapWith)) {
8969  6 return str;
8970    }
8971   
8972  7 return wrapWith.concat(str).concat(wrapWith);
8973    }
8974   
8975    /**
8976    * <p>
8977    * Wraps a string with a char if that char is missing from the start or end of the given string.
8978    * </p>
8979    *
8980    * <pre>
8981    * StringUtils.wrap(null, *) = null
8982    * StringUtils.wrap("", *) = ""
8983    * StringUtils.wrap("ab", '\0') = "ab"
8984    * StringUtils.wrap("ab", 'x') = "xabx"
8985    * StringUtils.wrap("ab", '\'') = "'ab'"
8986    * StringUtils.wrap("\"ab\"", '\"') = "\"ab\""
8987    * StringUtils.wrap("/", '/') = "/"
8988    * StringUtils.wrap("a/b/c", '/') = "/a/b/c/"
8989    * StringUtils.wrap("/a/b/c", '/') = "/a/b/c/"
8990    * StringUtils.wrap("a/b/c/", '/') = "/a/b/c/"
8991    * </pre>
8992    *
8993    * @param str
8994    * the string to be wrapped, may be {@code null}
8995    * @param wrapWith
8996    * the char that will wrap {@code str}
8997    * @return the wrapped string, or {@code null} if {@code str==null}
8998    * @since 3.5
8999    */
 
9000  15 toggle public static String wrapIfMissing(final String str, final char wrapWith) {
9001  15 if (isEmpty(str) || wrapWith == '\0') {
9002  3 return str;
9003    }
9004  12 final StringBuilder builder = new StringBuilder(str.length() + 2);
9005  12 if (str.charAt(0) != wrapWith) {
9006  8 builder.append(wrapWith);
9007    }
9008  12 builder.append(str);
9009  12 if (str.charAt(str.length() - 1) != wrapWith) {
9010  8 builder.append(wrapWith);
9011    }
9012  12 return builder.toString();
9013    }
9014   
9015    /**
9016    * <p>
9017    * Wraps a string with a string if that string is missing from the start or end of the given string.
9018    * </p>
9019    *
9020    * <pre>
9021    * StringUtils.wrap(null, *) = null
9022    * StringUtils.wrap("", *) = ""
9023    * StringUtils.wrap("ab", null) = "ab"
9024    * StringUtils.wrap("ab", "x") = "xabx"
9025    * StringUtils.wrap("ab", "\"") = "\"ab\""
9026    * StringUtils.wrap("\"ab\"", "\"") = "\"ab\""
9027    * StringUtils.wrap("ab", "'") = "'ab'"
9028    * StringUtils.wrap("'abcd'", "'") = "'abcd'"
9029    * StringUtils.wrap("\"abcd\"", "'") = "'\"abcd\"'"
9030    * StringUtils.wrap("'abcd'", "\"") = "\"'abcd'\""
9031    * StringUtils.wrap("/", "/") = "/"
9032    * StringUtils.wrap("a/b/c", "/") = "/a/b/c/"
9033    * StringUtils.wrap("/a/b/c", "/") = "/a/b/c/"
9034    * StringUtils.wrap("a/b/c/", "/") = "/a/b/c/"
9035    * </pre>
9036    *
9037    * @param str
9038    * the string to be wrapped, may be {@code null}
9039    * @param wrapWith
9040    * the char that will wrap {@code str}
9041    * @return the wrapped string, or {@code null} if {@code str==null}
9042    * @since 3.5
9043    */
 
9044  17 toggle public static String wrapIfMissing(final String str, final String wrapWith) {
9045  17 if (isEmpty(str) || isEmpty(wrapWith)) {
9046  3 return str;
9047    }
9048  14 final StringBuilder builder = new StringBuilder(str.length() + wrapWith.length() + wrapWith.length());
9049  14 if (!str.startsWith(wrapWith)) {
9050  9 builder.append(wrapWith);
9051    }
9052  14 builder.append(str);
9053  14 if (!str.endsWith(wrapWith)) {
9054  9 builder.append(wrapWith);
9055    }
9056  14 return builder.toString();
9057    }
9058   
9059    /**
9060    * <p>
9061    * Unwraps a given string from anther string.
9062    * </p>
9063    *
9064    * <pre>
9065    * StringUtils.unwrap(null, null) = null
9066    * StringUtils.unwrap(null, "") = null
9067    * StringUtils.unwrap(null, "1") = null
9068    * StringUtils.unwrap("\'abc\'", "\'") = "abc"
9069    * StringUtils.unwrap("\"abc\"", "\"") = "abc"
9070    * StringUtils.unwrap("AABabcBAA", "AA") = "BabcB"
9071    * StringUtils.unwrap("A", "#") = "A"
9072    * StringUtils.unwrap("#A", "#") = "#A"
9073    * StringUtils.unwrap("A#", "#") = "A#"
9074    * </pre>
9075    *
9076    * @param str
9077    * the String to be unwrapped, can be null
9078    * @param wrapToken
9079    * the String used to unwrap
9080    * @return unwrapped String or the original string
9081    * if it is not quoted properly with the wrapToken
9082    * @since 3.6
9083    */
 
9084  17 toggle public static String unwrap(final String str, final String wrapToken) {
9085  17 if (isEmpty(str) || isEmpty(wrapToken)) {
9086  7 return str;
9087    }
9088   
9089  10 if (startsWith(str, wrapToken) && endsWith(str, wrapToken)) {
9090  8 final int startIndex = str.indexOf(wrapToken);
9091  8 final int endIndex = str.lastIndexOf(wrapToken);
9092  8 final int wrapLength = wrapToken.length();
9093  8 if (startIndex != -1 && endIndex != -1) {
9094  8 return str.substring(startIndex + wrapLength, endIndex);
9095    }
9096    }
9097   
9098  2 return str;
9099    }
9100   
9101    /**
9102    * <p>
9103    * Unwraps a given string from a character.
9104    * </p>
9105    *
9106    * <pre>
9107    * StringUtils.unwrap(null, null) = null
9108    * StringUtils.unwrap(null, '\0') = null
9109    * StringUtils.unwrap(null, '1') = null
9110    * StringUtils.unwrap("\'abc\'", '\'') = "abc"
9111    * StringUtils.unwrap("AABabcBAA", 'A') = "ABabcBA"
9112    * StringUtils.unwrap("A", '#') = "A"
9113    * StringUtils.unwrap("#A", '#') = "#A"
9114    * StringUtils.unwrap("A#", '#') = "A#"
9115    * </pre>
9116    *
9117    * @param str
9118    * the String to be unwrapped, can be null
9119    * @param wrapChar
9120    * the character used to unwrap
9121    * @return unwrapped String or the original string
9122    * if it is not quoted properly with the wrapChar
9123    * @since 3.6
9124    */
 
9125  9 toggle public static String unwrap(final String str, final char wrapChar) {
9126  9 if (isEmpty(str) || wrapChar == '\0') {
9127  2 return str;
9128    }
9129   
9130  7 if (str.charAt(0) == wrapChar && str.charAt(str.length() - 1) == wrapChar) {
9131  4 final int startIndex = 0;
9132  4 final int endIndex = str.length() - 1;
9133  4 if (startIndex != -1 && endIndex != -1) {
9134  4 return str.substring(startIndex + 1, endIndex);
9135    }
9136    }
9137   
9138  3 return str;
9139    }
9140   
9141    /**
9142    * <p>Converts a {@code CharSequence} into an array of code points.</p>
9143    *
9144    * <p>Valid pairs of surrogate code units will be converted into a single supplementary
9145    * code point. Isolated surrogate code units (i.e. a high surrogate not followed by a low surrogate or
9146    * a low surrogate not preceeded by a high surrogate) will be returned as-is.</p>
9147    *
9148    * <pre>
9149    * StringUtils.toCodePoints(null) = null
9150    * StringUtils.toCodePoints("") = [] // empty array
9151    * </pre>
9152    *
9153    * @param str the character sequence to convert
9154    * @return an array of code points
9155    * @since 3.6
9156    */
 
9157  3 toggle public static int[] toCodePoints(CharSequence str) {
9158  3 if (str == null) {
9159  1 return null;
9160    }
9161  2 if (str.length() == 0) {
9162  1 return ArrayUtils.EMPTY_INT_ARRAY;
9163    }
9164   
9165  1 String s = str.toString();
9166  1 int[] result = new int[s.codePointCount(0, s.length())];
9167  1 int index = 0;
9168  9 for (int i = 0; i < result.length; i++) {
9169  8 result[i] = s.codePointAt(index);
9170  8 index += Character.charCount(result[i]);
9171    }
9172  1 return result;
9173    }
9174    }